mirror of
https://github.com/openappsec/openappsec.git
synced 2025-06-28 16:41:02 +03:00
Updating local policy, metrics, and local update trigger
This commit is contained in:
parent
9d848264f3
commit
a3014ab381
@ -4,7 +4,7 @@ project (ngen)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-terminate")
|
||||
|
||||
execute_process(COMMAND grep -c "Alpine Linux" /etc/os-release OUTPUT_VARIABLE IS_ALPINE)
|
||||
if(IS_ALPINE EQUAL "1")
|
||||
if(NOT IS_ALPINE EQUAL "0")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dalpine")
|
||||
endif()
|
||||
|
||||
|
@ -26,6 +26,7 @@ using OrchData = Maybe<std::string>;
|
||||
class I_UpdateCommunication
|
||||
{
|
||||
public:
|
||||
virtual void init() = 0;
|
||||
virtual Maybe<void> sendPolicyVersion(
|
||||
const std::string &policy_version,
|
||||
const std::string &policy_versions
|
||||
|
@ -13,6 +13,7 @@ add_library(local_policy_mgmt_gen
|
||||
local_policy_mgmt_gen.cc
|
||||
new_appsec_policy_crd_parser.cc
|
||||
new_appsec_linux_policy.cc
|
||||
new_auto_upgrade.cc
|
||||
new_custom_response.cc
|
||||
new_trusted_sources.cc
|
||||
new_log_trigger.cc
|
||||
|
@ -18,16 +18,12 @@ using namespace std;
|
||||
USE_DEBUG_FLAG(D_LOCAL_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
static const set<string> valid_modes = {"prevent", "detect", "inactive"};
|
||||
static const set<string> valid_units = {"minute", "second"};
|
||||
|
||||
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
|
||||
{ "prevent-learn", "Prevent"},
|
||||
{ "detect-learn", "Detect"},
|
||||
{ "prevent", "Prevent"},
|
||||
{ "detect", "Detect"},
|
||||
{ "inactive", "Inactive"}
|
||||
static const map<string, string> valid_modes_to_key = {
|
||||
{"prevent", "Active"},
|
||||
{"detect", "Detect"},
|
||||
{"inactive", "Inactive"}
|
||||
};
|
||||
static const set<string> valid_units = {"minute", "second"};
|
||||
|
||||
static const std::unordered_map<std::string, std::string> key_to_units_val = {
|
||||
{ "second", "Second"},
|
||||
@ -78,7 +74,7 @@ RateLimitSection::RateLimitSection(
|
||||
{
|
||||
bool any = asset_name == "Any" && url == "Any" && uri == "Any";
|
||||
string asset_id = any ? "Any" : url+uri;
|
||||
context = "assetId(" + asset_id + ")";
|
||||
context = any ? "All()" : "assetId(" + asset_id + ")";
|
||||
}
|
||||
|
||||
void
|
||||
@ -86,7 +82,7 @@ RateLimitSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("mode", key_to_mode_val.at(mode)),
|
||||
cereal::make_nvp("mode", mode),
|
||||
cereal::make_nvp("practiceId", practice_id),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("rules", rules)
|
||||
@ -180,9 +176,13 @@ void
|
||||
AccessControlRateLimit::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limit";
|
||||
parseAppsecJSONKey<string>("overrideMode", mode, archive_in, "Inactive");
|
||||
if (valid_modes.count(mode) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << mode;
|
||||
string in_mode;
|
||||
parseAppsecJSONKey<string>("overrideMode", in_mode, archive_in, "inactive");
|
||||
if (valid_modes_to_key.find(in_mode) == valid_modes_to_key.end()) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << in_mode;
|
||||
mode = "Inactive";
|
||||
} else {
|
||||
mode = valid_modes_to_key.at(in_mode);
|
||||
}
|
||||
parseAppsecJSONKey<std::vector<AccessControlRateLimiteRules>>("rules", rules, archive_in);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "appsec_practice_section.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -238,6 +239,7 @@ AppSecPracticeOpenSchemaAPI::getConfigMap() const
|
||||
{
|
||||
return config_map;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
void
|
||||
AppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
@ -272,6 +274,7 @@ AppSecPracticeSpec::getSnortSignatures() const
|
||||
{
|
||||
return snort_signatures;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
const AppSecPracticeWebAttacks &
|
||||
@ -337,6 +340,7 @@ ParsedMatch::ParsedMatch(const ExceptionMatch &exceptions)
|
||||
parsed_match.push_back(ParsedMatch(exception_match));
|
||||
}
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
@ -375,6 +379,7 @@ AppSecOverride::AppSecOverride(const InnerException &parsed_exceptions)
|
||||
map<string, string> behavior = {{parsed_exceptions.getBehaviorKey(), parsed_exceptions.getBehaviorValue()}};
|
||||
parsed_behavior.push_back(behavior);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
@ -426,10 +431,11 @@ WebAppSection::WebAppSection(
|
||||
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
|
||||
practice_advanced_config(parsed_appsec_spec),
|
||||
anti_bots(parsed_appsec_spec.getAntiBot()),
|
||||
trusted_sources({parsed_trusted_sources})
|
||||
trusted_sources({ parsed_trusted_sources })
|
||||
{
|
||||
web_attack_mitigation = true;
|
||||
web_attack_mitigation_action =
|
||||
web_attack_mitigation_mode != "Prevent" ? "Transparent" :
|
||||
web_attack_mitigation_severity == "critical" ? "low" :
|
||||
web_attack_mitigation_severity == "high" ? "balanced" :
|
||||
web_attack_mitigation_severity == "medium" ? "high" :
|
||||
@ -473,7 +479,7 @@ WebAppSection::WebAppSection(
|
||||
web_attack_mitigation_mode(_web_attack_mitigation_mode),
|
||||
practice_advanced_config(_practice_advanced_config),
|
||||
anti_bots(_anti_bots),
|
||||
trusted_sources({parsed_trusted_sources})
|
||||
trusted_sources({ parsed_trusted_sources })
|
||||
{
|
||||
web_attack_mitigation = true;
|
||||
web_attack_mitigation_action =
|
||||
@ -488,6 +494,7 @@ WebAppSection::WebAppSection(
|
||||
overrides.push_back(AppSecOverride(source_ident));
|
||||
}
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
@ -525,7 +532,16 @@ WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
cereal::make_nvp("botProtection_v2", detect_str)
|
||||
);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
bool
|
||||
WebAppSection::operator<(const WebAppSection &other) const
|
||||
{
|
||||
// for sorting from the most specific to the least specific rule
|
||||
return application_urls.size() > other.application_urls.size();
|
||||
}
|
||||
|
||||
void
|
||||
WebAPISection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
@ -554,8 +570,27 @@ WebAPISection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
cereal::make_nvp("overrides", empty_list)
|
||||
);
|
||||
}
|
||||
|
||||
bool
|
||||
WebAPISection::operator<(const WebAPISection &other) const
|
||||
{
|
||||
// for sorting from the most specific to the least specific rule
|
||||
return application_urls.size() > other.application_urls.size();
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
AppSecRulebase::AppSecRulebase(
|
||||
std::vector<WebAppSection> _webApplicationPractices,
|
||||
std::vector<WebAPISection> _webAPIPractices
|
||||
) :
|
||||
webApplicationPractices(_webApplicationPractices),
|
||||
webAPIPractices(_webAPIPractices)
|
||||
{
|
||||
sort(webAPIPractices.begin(), webAPIPractices.end());
|
||||
sort(webApplicationPractices.begin(), webApplicationPractices.end());
|
||||
}
|
||||
|
||||
void
|
||||
AppSecRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
@ -719,11 +754,7 @@ AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
|
||||
parseAppsecJSONKey<vector<AppSecCustomResponseSpec>>("custom-responses", custom_responses, archive_in);
|
||||
parseAppsecJSONKey<vector<AppsecException>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<vector<TrustedSourcesSpec>>("trusted-sources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>(
|
||||
"source-identifiers",
|
||||
sources_identifiers,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>("source-identifiers", sources_identifiers, archive_in);
|
||||
}
|
||||
|
||||
const AppsecPolicySpec &
|
||||
@ -768,7 +799,6 @@ AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
|
||||
const vector<RPMSettings> &
|
||||
AppsecLinuxPolicy::rpmGetRPSettings() const
|
||||
{
|
||||
|
@ -241,11 +241,21 @@ ExceptionMatch::ExceptionMatch(const NewAppsecException &parsed_exception)
|
||||
items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier()));
|
||||
}
|
||||
if (!parsed_exception.getSourceIp().empty()) {
|
||||
items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp()));
|
||||
items.push_back(ExceptionMatch("sourceIP", parsed_exception.getSourceIp()));
|
||||
}
|
||||
if (!parsed_exception.getUrl().empty()) {
|
||||
items.push_back(ExceptionMatch("url", parsed_exception.getUrl()));
|
||||
}
|
||||
|
||||
// when there is only one operand, there's no need for an additional 'and'/'or' condition enclosing it
|
||||
if (items.size() == 1) {
|
||||
auto & other = items[0];
|
||||
match_type = other.match_type;
|
||||
op = other.op;
|
||||
key = other.key;
|
||||
value = other.value;
|
||||
items = other.items;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -296,6 +296,8 @@ public:
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
bool operator< (const WebAppSection &other) const;
|
||||
|
||||
private:
|
||||
std::string application_urls;
|
||||
std::string asset_id;
|
||||
@ -350,6 +352,8 @@ public:
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
bool operator< (const WebAPISection &other) const;
|
||||
|
||||
private:
|
||||
std::string application_urls;
|
||||
std::string asset_id;
|
||||
@ -371,10 +375,7 @@ class AppSecRulebase
|
||||
public:
|
||||
AppSecRulebase(
|
||||
std::vector<WebAppSection> _webApplicationPractices,
|
||||
std::vector<WebAPISection> _webAPIPractices)
|
||||
:
|
||||
webApplicationPractices(_webApplicationPractices),
|
||||
webAPIPractices(_webAPIPractices) {}
|
||||
std::vector<WebAPISection> _webAPIPractices);
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "new_practice.h"
|
||||
#include "access_control_practice.h"
|
||||
#include "new_trusted_sources.h"
|
||||
|
||||
#include "new_auto_upgrade.h"
|
||||
|
||||
class V1beta2AppsecLinuxPolicy : Singleton::Consume<I_Environment>
|
||||
{
|
||||
@ -48,7 +48,8 @@ public:
|
||||
const std::vector<NewAppSecCustomResponse> &_custom_responses,
|
||||
const std::vector<NewAppsecException> &_exceptions,
|
||||
const std::vector<NewTrustedSourcesSpec> &_trusted_sources,
|
||||
const std::vector<NewSourcesIdentifiers> &_sources_identifiers)
|
||||
const std::vector<NewSourcesIdentifiers> &_sources_identifiers,
|
||||
const AppSecAutoUpgradeSpec &_auto_upgrade)
|
||||
:
|
||||
policies(_policies),
|
||||
threat_prevection_practices(_threat_prevention_practices),
|
||||
@ -57,7 +58,8 @@ public:
|
||||
custom_responses(_custom_responses),
|
||||
exceptions(_exceptions),
|
||||
trusted_sources(_trusted_sources),
|
||||
sources_identifiers(_sources_identifiers) {}
|
||||
sources_identifiers(_sources_identifiers),
|
||||
auto_upgrade(_auto_upgrade) {}
|
||||
// LCOV_EXCL_STOP
|
||||
void serialize(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
@ -69,6 +71,7 @@ public:
|
||||
const std::vector<NewAppsecException> & getAppsecExceptions() const;
|
||||
const std::vector<NewTrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
|
||||
const std::vector<NewSourcesIdentifiers> & getAppsecSourceIdentifierSpecs() const;
|
||||
const AppSecAutoUpgradeSpec & getAppSecAutoUpgradeSpec() const;
|
||||
void addSpecificRule(const NewParsedRule &_rule);
|
||||
|
||||
private:
|
||||
@ -80,6 +83,7 @@ private:
|
||||
std::vector<NewAppsecException> exceptions;
|
||||
std::vector<NewTrustedSourcesSpec> trusted_sources;
|
||||
std::vector<NewSourcesIdentifiers> sources_identifiers;
|
||||
AppSecAutoUpgradeSpec auto_upgrade;
|
||||
};
|
||||
|
||||
#endif // __NEW_APPSEC_LINUX_POLICY_H__
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
const std::string & getSourceIdentifiers() const;
|
||||
const std::string & getCustomResponse() const;
|
||||
const std::string & getTrustedSources() const;
|
||||
const std::string & getUpgradeSettings() const;
|
||||
const std::string & getHost() const;
|
||||
const std::string & getMode() const;
|
||||
|
||||
@ -56,6 +57,7 @@ private:
|
||||
std::string source_identifiers;
|
||||
std::string custom_response;
|
||||
std::string trusted_sources;
|
||||
std::string upgrade_settings;
|
||||
std::string host;
|
||||
std::string mode;
|
||||
};
|
||||
|
47
components/security_apps/local_policy_mgmt_gen/include/new_auto_upgrade.h
Executable file
47
components/security_apps/local_policy_mgmt_gen/include/new_auto_upgrade.h
Executable file
@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __NEW_AUTO_UPGRADE_H__
|
||||
#define __NEW_AUTO_UPGRADE_H__
|
||||
|
||||
#include <string>
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "local_policy_common.h"
|
||||
|
||||
class AppSecAutoUpgradeSpec
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
void save(cereal::JSONOutputArchive& out_ar) const;
|
||||
|
||||
const std::string & getAppSecClassName() const;
|
||||
const std::string & getName() const;
|
||||
void setName(const std::string &_name);
|
||||
|
||||
private:
|
||||
std::string mode = "automatic";
|
||||
std::vector<std::string> days;
|
||||
std::string upgrade_window_start_hour_UTC;
|
||||
uint upgrade_window_duration;
|
||||
|
||||
std::string name;
|
||||
std::string appsec_class_name;
|
||||
};
|
||||
|
||||
#endif // __NEW_AUTO_UPGRADE_H__
|
@ -30,9 +30,11 @@ class NewAppsecTriggerAccessControlLogging
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isAcAllowEvents() const { return ac_allow_events; }
|
||||
bool isAcDropEvents() const { return ac_drop_events; }
|
||||
private:
|
||||
bool allow_events = false;
|
||||
bool drop_events = false;
|
||||
bool ac_allow_events = false;
|
||||
bool ac_drop_events = false;
|
||||
};
|
||||
|
||||
class NewAppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
|
||||
@ -158,6 +160,7 @@ public:
|
||||
const NewAppsecTriggerLogging & getAppsecTriggerLogging() const;
|
||||
const NewAppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
|
||||
const NewAppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
|
||||
const NewAppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const;
|
||||
|
||||
private:
|
||||
NewAppsecTriggerAccessControlLogging access_control_logging;
|
||||
|
@ -481,17 +481,22 @@ private:
|
||||
class NewSnortSignaturesAndOpenSchemaAPI
|
||||
{
|
||||
public:
|
||||
NewSnortSignaturesAndOpenSchemaAPI() : is_temporary(false) {};
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
void addFile(const std::string &file_name);
|
||||
const std::string & getOverrideMode() const;
|
||||
const std::vector<std::string> & getConfigMap() const;
|
||||
const std::vector<std::string> & getFiles() const;
|
||||
bool isTemporary() const;
|
||||
void setTemporary(bool val);
|
||||
|
||||
private:
|
||||
std::string override_mode;
|
||||
std::vector<std::string> config_map;
|
||||
std::vector<std::string> files;
|
||||
bool is_temporary;
|
||||
};
|
||||
|
||||
class NewAppSecWebBotsURI
|
||||
|
17
components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h
Executable file → Normal file
17
components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h
Executable file → Normal file
@ -51,6 +51,7 @@ enum class AnnotationTypes {
|
||||
WEB_USER_RES,
|
||||
SOURCE_IDENTIFIERS,
|
||||
TRUSTED_SOURCES,
|
||||
UPGRADE_SETTINGS,
|
||||
COUNT
|
||||
};
|
||||
|
||||
@ -96,16 +97,17 @@ class PolicyWrapper
|
||||
{
|
||||
public:
|
||||
PolicyWrapper(
|
||||
const SettingsWrapper &_settings,
|
||||
const SettingsRulebase &_settings,
|
||||
const SecurityAppsWrapper &_security_apps)
|
||||
:
|
||||
settings(_settings),
|
||||
security_apps(_security_apps) {}
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const SettingsRulebase & getSettings() const { return settings; }
|
||||
const SecurityAppsWrapper & getSecurityApps() const { return security_apps; }
|
||||
|
||||
private:
|
||||
SettingsWrapper settings;
|
||||
SettingsRulebase settings;
|
||||
SecurityAppsWrapper security_apps;
|
||||
};
|
||||
|
||||
@ -139,7 +141,11 @@ private:
|
||||
|
||||
std::tuple<std::string, std::string, std::string> splitHostName(const std::string &host_name);
|
||||
|
||||
std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path);
|
||||
std::string dumpPolicyToFile(
|
||||
const PolicyWrapper &policy,
|
||||
const std::string &policy_path,
|
||||
const std::string &settings_path = "/etc/cp/conf/settings.json"
|
||||
);
|
||||
|
||||
PolicyWrapper combineElementsToPolicy(const std::string &policy_version);
|
||||
|
||||
@ -155,7 +161,7 @@ private:
|
||||
std::map<AnnotationTypes, std::string> &rule_annotations
|
||||
);
|
||||
|
||||
void createSnortProtecionsSection(const std::string &file_name, const std::string &practic_name);
|
||||
void createSnortProtecionsSection(const std::string &file_name, bool is_temporary);
|
||||
|
||||
void
|
||||
createSnortSections(
|
||||
@ -245,6 +251,7 @@ private:
|
||||
std::map<std::string, RateLimitSection> rate_limit;
|
||||
std::map<std::string, UsersIdentifiersRulebase> users_identifiers;
|
||||
std::map<std::string, AppSecTrustedSources> trusted_sources;
|
||||
AppSecAutoUpgradeSpec upgrade_settings;
|
||||
};
|
||||
|
||||
template<class T, class R>
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "local_policy_common.h"
|
||||
#include "new_auto_upgrade.h"
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
class AgentSettingsSection
|
||||
@ -41,12 +42,18 @@ private:
|
||||
class SettingsRulebase
|
||||
{
|
||||
public:
|
||||
SettingsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
|
||||
SettingsRulebase(
|
||||
std::vector<AgentSettingsSection> _agentSettings,
|
||||
const AppSecAutoUpgradeSpec &_upgradeSettings)
|
||||
:
|
||||
agentSettings(_agentSettings),
|
||||
upgrade_settings(_upgradeSettings) {}
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<AgentSettingsSection> agentSettings;
|
||||
AppSecAutoUpgradeSpec upgrade_settings;
|
||||
};
|
||||
|
||||
class SettingsWrapper
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
bool _responseBody,
|
||||
bool _tpDetect,
|
||||
bool _tpPrevent,
|
||||
bool _acAllow,
|
||||
bool _acDrop,
|
||||
bool _webBody,
|
||||
bool _webHeaders,
|
||||
bool _webRequests,
|
||||
@ -76,6 +78,8 @@ private:
|
||||
bool responseBody;
|
||||
bool tpDetect;
|
||||
bool tpPrevent;
|
||||
bool acAllow;
|
||||
bool acDrop;
|
||||
bool webBody;
|
||||
bool webHeaders;
|
||||
bool webRequests;
|
||||
@ -158,9 +162,11 @@ class AppsecTriggerAccessControlLogging
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isAcAllowEvents() const { return ac_allow_events; }
|
||||
bool isAcDropEvents() const { return ac_drop_events; }
|
||||
private:
|
||||
bool allow_events = false;
|
||||
bool drop_events = false;
|
||||
bool ac_allow_events = false;
|
||||
bool ac_drop_events = false;
|
||||
};
|
||||
|
||||
class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
|
||||
@ -281,6 +287,7 @@ public:
|
||||
const AppsecTriggerLogging & getAppsecTriggerLogging() const;
|
||||
const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
|
||||
const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
|
||||
const AppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const;
|
||||
|
||||
private:
|
||||
AppsecTriggerAccessControlLogging access_control_logging;
|
||||
|
@ -159,6 +159,7 @@ extractElementsFromNewRule(
|
||||
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(rule.getCustomResponse());
|
||||
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(rule.getSourceIdentifiers());
|
||||
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(rule.getTrustedSources());
|
||||
policy_elements_names[AnnotationTypes::UPGRADE_SETTINGS].insert(rule.getUpgradeSettings());
|
||||
}
|
||||
|
||||
map<AnnotationTypes, unordered_set<string>>
|
||||
@ -356,8 +357,9 @@ K8sPolicyUtils::createSnortFile(vector<NewAppSecPracticeSpec> &practices) const
|
||||
{
|
||||
for (NewAppSecPracticeSpec &practice : practices) {
|
||||
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<K8sPolicyUtils>();
|
||||
auto path = "/etc/cp/conf/snort/snort_k8s_" + practice.getName() + ".rule";
|
||||
auto path = getFilesystemPathConfig() + "/conf/snort/snort_k8s_" + practice.getName() + ".rule";
|
||||
bool append_mode = false;
|
||||
practice.getSnortSignatures().setTemporary(true);
|
||||
for (const string &config_map : practice.getSnortSignatures().getConfigMap())
|
||||
{
|
||||
auto maybe_configmap = getObjectFromCluster<ConfigMaps>(
|
||||
@ -441,6 +443,15 @@ K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
|
||||
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES]
|
||||
);
|
||||
|
||||
vector<AppSecAutoUpgradeSpec> vec_upgrade_settings = extractV1Beta2ElementsFromCluster<AppSecAutoUpgradeSpec>(
|
||||
"autoupgrade",
|
||||
policy_elements_names[AnnotationTypes::UPGRADE_SETTINGS]
|
||||
);
|
||||
if (vec_upgrade_settings.size() > 1) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Only one definition of upgrade settings is required.";
|
||||
}
|
||||
auto upgrade_settings = vec_upgrade_settings.empty() ? AppSecAutoUpgradeSpec() : vec_upgrade_settings.front();
|
||||
|
||||
V1beta2AppsecLinuxPolicy appsec_policy = V1beta2AppsecLinuxPolicy(
|
||||
appsec_policy_spec.getSpec(),
|
||||
threat_prevention_practices,
|
||||
@ -449,7 +460,8 @@ K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
|
||||
web_user_responses,
|
||||
exceptions,
|
||||
trusted_sources,
|
||||
source_identifiers
|
||||
source_identifiers,
|
||||
upgrade_settings
|
||||
);
|
||||
return appsec_policy;
|
||||
}
|
||||
|
@ -64,6 +64,12 @@ V1beta2AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
const AppSecAutoUpgradeSpec &
|
||||
V1beta2AppsecLinuxPolicy::getAppSecAutoUpgradeSpec() const
|
||||
{
|
||||
return auto_upgrade;
|
||||
}
|
||||
|
||||
void
|
||||
V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule)
|
||||
{
|
||||
@ -97,4 +103,5 @@ V1beta2AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
|
||||
parseAppsecJSONKey<vector<NewAppsecException>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<vector<NewTrustedSourcesSpec>>("trustedSources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<vector<NewSourcesIdentifiers>>("sourcesIdentifiers", sources_identifiers, archive_in);
|
||||
parseAppsecJSONKey<AppSecAutoUpgradeSpec>("autoUpgrade", auto_upgrade, archive_in);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ NewParsedRule::load(cereal::JSONInputArchive &archive_in)
|
||||
parseAppsecJSONKey<string>("customResponse", custom_response, archive_in);
|
||||
parseAppsecJSONKey<string>("sourceIdentifiers", source_identifiers, archive_in);
|
||||
parseAppsecJSONKey<string>("trustedSources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<string>("autoUpgrade", upgrade_settings, archive_in);
|
||||
try {
|
||||
archive_in(cereal::make_nvp("host", host));
|
||||
} catch (const cereal::Exception &e)
|
||||
@ -86,6 +87,12 @@ NewParsedRule::getTrustedSources() const
|
||||
return trusted_sources;
|
||||
}
|
||||
|
||||
const string &
|
||||
NewParsedRule::getUpgradeSettings() const
|
||||
{
|
||||
return upgrade_settings;
|
||||
}
|
||||
|
||||
const string &
|
||||
NewParsedRule::getHost() const
|
||||
{
|
||||
|
118
components/security_apps/local_policy_mgmt_gen/new_auto_upgrade.cc
Executable file
118
components/security_apps/local_policy_mgmt_gen/new_auto_upgrade.cc
Executable file
@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "new_auto_upgrade.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_LOCAL_POLICY);
|
||||
|
||||
static const set<string> valid_modes = {"automatic", "manual", "scheduled"};
|
||||
static const set<string> valid_days_of_week = {
|
||||
"monday",
|
||||
"tuesday",
|
||||
"wednesday",
|
||||
"thursday",
|
||||
"friday",
|
||||
"saturday",
|
||||
"sunday"
|
||||
};
|
||||
|
||||
class AppSecScheduledUpgrade
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<vector<string>>("days", days, archive_in);
|
||||
for (const string &day : days) {
|
||||
if (valid_days_of_week.count(day) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec upgrade day invalid: " << day;
|
||||
}
|
||||
}
|
||||
parseAppsecJSONKey<string>("upgradeWindowStartHourUTC", upgrade_window_start_hour_UTC, archive_in, "0:00");
|
||||
parseAppsecJSONKey<uint>("upgradeWindowDuration", upgrade_window_duration, archive_in, 4);
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
getDays() const
|
||||
{
|
||||
return days;
|
||||
}
|
||||
|
||||
const string &
|
||||
getUpgradeWindowStartHourUTC() const
|
||||
{
|
||||
return upgrade_window_start_hour_UTC;
|
||||
}
|
||||
|
||||
const uint &
|
||||
getUpgradeWindowDuration() const
|
||||
{
|
||||
return upgrade_window_duration;
|
||||
}
|
||||
|
||||
private:
|
||||
vector<string> days;
|
||||
string upgrade_window_start_hour_UTC = "0:00";
|
||||
uint upgrade_window_duration = 4;
|
||||
};
|
||||
|
||||
void
|
||||
AppSecAutoUpgradeSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec upgrade settings spec";
|
||||
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("mode", mode, archive_in);
|
||||
if (valid_modes.count(mode) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec upgrade mode invalid: " << mode;
|
||||
}
|
||||
if (mode != "scheduled") return;
|
||||
|
||||
AppSecScheduledUpgrade schedule;
|
||||
parseAppsecJSONKey<AppSecScheduledUpgrade>("schedule", schedule, archive_in);
|
||||
days = schedule.getDays();
|
||||
upgrade_window_start_hour_UTC = schedule.getUpgradeWindowStartHourUTC();
|
||||
upgrade_window_duration = schedule.getUpgradeWindowDuration();
|
||||
}
|
||||
|
||||
void
|
||||
AppSecAutoUpgradeSpec::save(cereal::JSONOutputArchive& out_ar) const
|
||||
{
|
||||
out_ar(cereal::make_nvp("upgradeMode", mode));
|
||||
if (mode != "scheduled") return;
|
||||
out_ar(
|
||||
cereal::make_nvp("upgradeTime", upgrade_window_start_hour_UTC),
|
||||
cereal::make_nvp("upgradeDurationHours", upgrade_window_duration),
|
||||
cereal::make_nvp("upgradeDay", days)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
AppSecAutoUpgradeSpec::setName(const string &_name)
|
||||
{
|
||||
name = _name;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecAutoUpgradeSpec::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecAutoUpgradeSpec::getAppSecClassName() const
|
||||
{
|
||||
return appsec_class_name;
|
||||
}
|
@ -23,9 +23,9 @@ static const set<string> valid_actions = {"skip", "accept", "drop", "suppressLog
|
||||
void
|
||||
NewAppsecExceptionCondition::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception condition";
|
||||
parseAppsecJSONKey<string>("key", key, archive_in);
|
||||
parseAppsecJSONKey<string>("value", value, archive_in);
|
||||
dbgTrace(D_LOCAL_POLICY) << "Key: " << key << " Value: " << value;
|
||||
}
|
||||
|
||||
const string &
|
||||
|
@ -26,8 +26,8 @@ void
|
||||
NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging";
|
||||
parseAppsecJSONKey<bool>("allowEvents", allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("dropEvents", drop_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("allowEvents", ac_allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("dropEvents", ac_drop_events, archive_in, false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -307,6 +307,13 @@ NewAppsecLogTrigger::getAppsecTriggerLogging() const
|
||||
return appsec_logging;
|
||||
}
|
||||
|
||||
const NewAppsecTriggerAccessControlLogging &
|
||||
NewAppsecLogTrigger::getAppsecTriggerAccessControlLogging() const
|
||||
{
|
||||
return access_control_logging;
|
||||
}
|
||||
|
||||
|
||||
const NewAppsecTriggerExtendedLogging &
|
||||
NewAppsecLogTrigger::getAppsecTriggerExtendedLogging() const
|
||||
{
|
||||
|
@ -107,9 +107,9 @@ void
|
||||
NewAppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Attack Protections";
|
||||
parseAppsecJSONKey<string>("csrfEnabled", csrf_protection, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("errorDisclosureEnabled", error_disclosure, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("openRedirectEnabled", open_redirect, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("csrfProtection", csrf_protection, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("errorDisclosure", error_disclosure, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("openRedirect", open_redirect, archive_in, "inactive");
|
||||
parseAppsecJSONKey<bool>("nonValidHttpMethods", non_valid_http_methods, archive_in, false);
|
||||
}
|
||||
|
||||
@ -441,6 +441,8 @@ NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in)
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice";
|
||||
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
|
||||
parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("files", files, archive_in);
|
||||
is_temporary = false;
|
||||
if (valid_modes.count(override_mode) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode;
|
||||
}
|
||||
@ -470,6 +472,18 @@ NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const
|
||||
return config_map;
|
||||
}
|
||||
|
||||
bool
|
||||
NewSnortSignaturesAndOpenSchemaAPI::isTemporary() const
|
||||
{
|
||||
return is_temporary;
|
||||
}
|
||||
|
||||
void
|
||||
NewSnortSignaturesAndOpenSchemaAPI::setTemporary(bool val)
|
||||
{
|
||||
is_temporary = val;
|
||||
}
|
||||
|
||||
void
|
||||
IpsProtectionsRulesSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
|
@ -38,12 +38,6 @@ SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
security_apps.save(out_ar);
|
||||
}
|
||||
|
||||
string
|
||||
PolicyMakerUtils::getPolicyName(const string &policy_path)
|
||||
{
|
||||
@ -150,16 +144,19 @@ PolicyMakerUtils::splitHostName(const string &host_name)
|
||||
}
|
||||
|
||||
string
|
||||
PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &policy_path)
|
||||
PolicyMakerUtils::dumpPolicyToFile(
|
||||
const PolicyWrapper &policy,
|
||||
const string &policy_path,
|
||||
const string &settings_path)
|
||||
{
|
||||
clearElementsMaps();
|
||||
|
||||
stringstream ss;
|
||||
stringstream policy_ss, settings_ss;
|
||||
{
|
||||
cereal::JSONOutputArchive ar(ss);
|
||||
policy.save(ar);
|
||||
cereal::JSONOutputArchive ar(policy_ss);
|
||||
policy.getSecurityApps().save(ar);
|
||||
}
|
||||
string policy_str = ss.str();
|
||||
string policy_str = policy_ss.str();
|
||||
try {
|
||||
ofstream policy_file(policy_path);
|
||||
policy_file << policy_str;
|
||||
@ -169,6 +166,20 @@ PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &po
|
||||
return "";
|
||||
}
|
||||
|
||||
{
|
||||
cereal::JSONOutputArchive ar(settings_ss);
|
||||
policy.getSettings().save(ar);
|
||||
}
|
||||
string settings_str = settings_ss.str();
|
||||
try {
|
||||
ofstream settings_file(settings_path);
|
||||
settings_file << settings_str;
|
||||
settings_file.close();
|
||||
} catch (const ofstream::failure &e) {
|
||||
dbgDebug(D_NGINX_POLICY) << "Error while writing settings to " << settings_path << ", Error: " << e.what();
|
||||
}
|
||||
dbgDebug(D_LOCAL_POLICY) << settings_path << " content: " << settings_str;
|
||||
|
||||
return policy_str;
|
||||
}
|
||||
|
||||
@ -517,6 +528,8 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
|
||||
trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity();
|
||||
bool tpDetect = trigger_spec.getAppsecTriggerLogging().isDetectEvents();
|
||||
bool tpPrevent = trigger_spec.getAppsecTriggerLogging().isPreventEvents();
|
||||
bool acAllow = trigger_spec.getAppsecTriggerAccessControlLogging().isAcAllowEvents();
|
||||
bool acDrop = trigger_spec.getAppsecTriggerAccessControlLogging().isAcDropEvents();
|
||||
bool webRequests = trigger_spec.getAppsecTriggerLogging().isAllWebRequests();
|
||||
bool webUrlPath = trigger_spec.getAppsecTriggerExtendedLogging().isUrlPath();
|
||||
bool webUrlQuery = trigger_spec.getAppsecTriggerExtendedLogging().isUrlQuery();
|
||||
@ -555,6 +568,8 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
|
||||
responseBody,
|
||||
tpDetect,
|
||||
tpPrevent,
|
||||
acAllow,
|
||||
acDrop,
|
||||
webBody,
|
||||
webHeaders,
|
||||
webRequests,
|
||||
@ -1004,13 +1019,21 @@ PolicyMakerUtils::createIpsSections(
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, const string &practice_name)
|
||||
PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, bool is_temporary)
|
||||
{
|
||||
auto path = getFilesystemPathConfig() + "/conf/snort/snort_k8s_" + practice_name;
|
||||
if (snort_protections.find(path) != snort_protections.end()) return;
|
||||
auto path = getFilesystemPathConfig() + "/conf/snort/" + file_name;
|
||||
string in_file = is_temporary ? path + ".rule" : path;
|
||||
|
||||
auto snort_scriipt_path = getFilesystemPathConfig() + "/scripts/snort_to_ips_local.py";
|
||||
auto cmd = "python " + snort_scriipt_path + " " + path + ".rule " + path + ".out " + path + ".err";
|
||||
if (snort_protections.find(path) != snort_protections.end()) {
|
||||
dbgTrace(D_LOCAL_POLICY) << "Snort protections section for file " << file_name << " already exists";
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_LOCAL_POLICY)
|
||||
<< "Reading snort signatures from"
|
||||
<< (is_temporary ? " temporary" : "") << " file " << path;
|
||||
|
||||
auto snort_script_path = getFilesystemPathConfig() + "/scripts/snort_to_ips_local.py";
|
||||
auto cmd = "python3 " + snort_script_path + " " + in_file + " " + path + ".out " + path + ".err";
|
||||
|
||||
auto res = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(cmd);
|
||||
|
||||
@ -1026,7 +1049,7 @@ PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, const st
|
||||
}
|
||||
|
||||
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalPolicyMgmtGenerator>();
|
||||
i_orchestration_tools->removeFile(path + ".rule");
|
||||
if (is_temporary) i_orchestration_tools->removeFile(in_file);
|
||||
i_orchestration_tools->removeFile(path + ".out");
|
||||
i_orchestration_tools->removeFile(path + ".err");
|
||||
|
||||
@ -1055,7 +1078,14 @@ PolicyMakerUtils::createSnortSections(
|
||||
apssec_practice.getSnortSignatures().getFiles().size() == 0) {
|
||||
return;
|
||||
}
|
||||
createSnortProtecionsSection(apssec_practice.getSnortSignatures().getFiles()[0], apssec_practice.getName());
|
||||
|
||||
if (apssec_practice.getSnortSignatures().isTemporary()) {
|
||||
createSnortProtecionsSection("snort_k8s_" + apssec_practice.getName(), true);
|
||||
} else if (apssec_practice.getSnortSignatures().getFiles().size() > 0) {
|
||||
// when support for multiple files is ready, will iterate over the files array
|
||||
auto file = apssec_practice.getSnortSignatures().getFiles()[0];
|
||||
createSnortProtecionsSection(file, false);
|
||||
}
|
||||
|
||||
SnortProtectionsSection snort_section = SnortProtectionsSection(
|
||||
context,
|
||||
@ -1160,7 +1190,7 @@ PolicyMakerUtils::createWebAppSection(
|
||||
apssec_practice.getWebAttacks().getMaxUrlSizeBytes()
|
||||
);
|
||||
WebAppSection web_app = WebAppSection(
|
||||
full_url == "Any" ? "" : full_url,
|
||||
full_url == "Any" ? "http://*:*" : full_url,
|
||||
rule_config.getAssetId(),
|
||||
rule_config.getAssetName(),
|
||||
rule_config.getAssetId(),
|
||||
@ -1271,17 +1301,16 @@ PolicyMakerUtils::createThreatPreventionPracticeSections(
|
||||
|
||||
}
|
||||
|
||||
SettingsWrapper
|
||||
createProfilesSection()
|
||||
SettingsRulebase
|
||||
createSettingsSection(const AppSecAutoUpgradeSpec &upgrade_settings)
|
||||
{
|
||||
string agent_settings_key = "agent.test.policy";
|
||||
string agent_settings_value = "local policy";
|
||||
AgentSettingsSection agent_setting_1 = AgentSettingsSection(agent_settings_key, agent_settings_value);
|
||||
|
||||
SettingsRulebase settings_rulebase_1 = SettingsRulebase({agent_setting_1});
|
||||
return SettingsWrapper(settings_rulebase_1);
|
||||
return SettingsRulebase({agent_setting_1}, upgrade_settings);
|
||||
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
PolicyWrapper
|
||||
PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
|
||||
@ -1313,8 +1342,8 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
|
||||
policy_version
|
||||
);
|
||||
|
||||
SettingsWrapper profiles_section = createProfilesSection();
|
||||
PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section);
|
||||
SettingsRulebase settings_section = createSettingsSection(upgrade_settings);
|
||||
PolicyWrapper policy_wrapper = PolicyWrapper(settings_section, security_app_section);
|
||||
|
||||
return policy_wrapper;
|
||||
}
|
||||
@ -1433,7 +1462,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
|
||||
|
||||
if (!web_apps.count(rule_config.getAssetName())) {
|
||||
WebAppSection web_app = WebAppSection(
|
||||
full_url == "Any" ? "" : full_url,
|
||||
full_url == "Any" ? "http://*:*" : full_url,
|
||||
rule_config.getAssetId(),
|
||||
rule_config.getAssetName(),
|
||||
rule_config.getAssetId(),
|
||||
@ -1553,6 +1582,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
rule_annotations
|
||||
);
|
||||
|
||||
upgrade_settings = policy.getAppSecAutoUpgradeSpec();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
|
@ -35,6 +35,8 @@ LogTriggerSection::LogTriggerSection(
|
||||
bool _responseBody,
|
||||
bool _tpDetect,
|
||||
bool _tpPrevent,
|
||||
bool _acAllow,
|
||||
bool _acDrop,
|
||||
bool _webBody,
|
||||
bool _webHeaders,
|
||||
bool _webRequests,
|
||||
@ -58,6 +60,8 @@ LogTriggerSection::LogTriggerSection(
|
||||
responseBody(_responseBody),
|
||||
tpDetect(_tpDetect),
|
||||
tpPrevent(_tpPrevent),
|
||||
acAllow(_acAllow),
|
||||
acDrop(_acDrop),
|
||||
webBody(_webBody),
|
||||
webHeaders(_webHeaders),
|
||||
webRequests(_webRequests),
|
||||
@ -88,8 +92,8 @@ LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("triggerType", trigger_type),
|
||||
cereal::make_nvp("verbosity", verbosity),
|
||||
cereal::make_nvp("acAllow", false),
|
||||
cereal::make_nvp("acDrop", false),
|
||||
cereal::make_nvp("acAllow", acAllow),
|
||||
cereal::make_nvp("acDrop", acDrop),
|
||||
cereal::make_nvp("complianceViolations", false),
|
||||
cereal::make_nvp("complianceWarnings", false),
|
||||
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
|
||||
@ -242,8 +246,8 @@ void
|
||||
AppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging";
|
||||
parseAppsecJSONKey<bool>("allow-events", allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("drop-events", drop_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("allow-events", ac_allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("drop-events", ac_drop_events, archive_in, false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -526,6 +530,13 @@ AppsecTriggerSpec::getAppsecTriggerLogDestination() const
|
||||
return log_destination;
|
||||
}
|
||||
|
||||
const AppsecTriggerAccessControlLogging &
|
||||
AppsecTriggerSpec::getAppsecTriggerAccessControlLogging() const
|
||||
{
|
||||
return access_control_logging;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TriggersWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_orchestration_status.h"
|
||||
#include "i_messaging.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "i_details_resolver.h"
|
||||
@ -23,6 +22,7 @@
|
||||
#include "i_shell_cmd.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "i_env_details.h"
|
||||
#include "i_declarative_policy.h"
|
||||
#include "maybe_res.h"
|
||||
#include "event.h"
|
||||
#include "rest.h"
|
||||
@ -43,6 +43,7 @@ private:
|
||||
|
||||
class DeclarativePolicyUtils
|
||||
:
|
||||
public Singleton::Provide<I_DeclarativePolicy>::SelfInterface,
|
||||
public Singleton::Consume<I_ShellCmd>,
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>,
|
||||
Singleton::Consume<I_EnvDetails>,
|
||||
@ -75,13 +76,12 @@ public:
|
||||
const std::string &tenant_id,
|
||||
const std::string &profile_id,
|
||||
const std::string &fog_address
|
||||
);
|
||||
std::string getUpdate(CheckUpdateRequest &request);
|
||||
bool shouldApplyPolicy();
|
||||
void turnOffApplyPolicyFlag();
|
||||
) override;
|
||||
std::string getUpdate(CheckUpdateRequest &request) override;
|
||||
bool shouldApplyPolicy() override;
|
||||
void turnOffApplyPolicyFlag() override;
|
||||
|
||||
std::string getCurrVersion() { return curr_version; }
|
||||
std::string getCurrPolicy() { return curr_policy; }
|
||||
std::string getCurrPolicy() override { return curr_policy; }
|
||||
|
||||
void upon(const ApplyPolicyEvent &event) override;
|
||||
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
) const override;
|
||||
|
||||
private:
|
||||
DeclarativePolicyUtils declarative_policy_utils;
|
||||
I_DeclarativePolicy *i_declarative_policy = nullptr;
|
||||
};
|
||||
|
||||
#endif // __FOG_COMMUNICATION_H__
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
private:
|
||||
Maybe<std::string> getNewVersion();
|
||||
|
||||
DeclarativePolicyUtils declarative_policy_utils;
|
||||
I_DeclarativePolicy *i_declarative_policy = nullptr;
|
||||
};
|
||||
|
||||
#endif // __HYBRID_COMMUNICATION_H__
|
||||
|
@ -0,0 +1,32 @@
|
||||
#ifndef __I_DECLARATIVE_POLICY__
|
||||
#define __I_DECLARATIVE_POLICY__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "singleton.h"
|
||||
#include "orchestrator/rest_api/orchestration_check_update.h"
|
||||
|
||||
class I_DeclarativePolicy
|
||||
{
|
||||
public:
|
||||
virtual bool shouldApplyPolicy() = 0;
|
||||
|
||||
virtual std::string getUpdate(CheckUpdateRequest &request) = 0;
|
||||
|
||||
virtual void sendUpdatesToFog(
|
||||
const std::string &access_token,
|
||||
const std::string &tenant_id,
|
||||
const std::string &profile_id,
|
||||
const std::string &fog_address
|
||||
) = 0;
|
||||
|
||||
virtual std::string getCurrPolicy() = 0;
|
||||
|
||||
virtual void turnOffApplyPolicyFlag() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_DeclarativePolicy() {}
|
||||
};
|
||||
|
||||
|
||||
#endif // __I_DECLARATIVE_POLICY__
|
@ -27,9 +27,13 @@ class MockUpdateCommunication :
|
||||
public Singleton::Provide<I_UpdateCommunication>::From<MockProvider<I_UpdateCommunication>>
|
||||
{
|
||||
public:
|
||||
void init() {}
|
||||
MOCK_METHOD0(authenticateAgent, Maybe<void>());
|
||||
MOCK_METHOD1(getUpdate, Maybe<void>(CheckUpdateRequest &));
|
||||
MOCK_METHOD1(downloadAttributeFile, Maybe<std::string>(const GetResourceFile &));
|
||||
MOCK_METHOD2(
|
||||
downloadAttributeFile,
|
||||
Maybe<std::string>(const GetResourceFile &, const std::string &)
|
||||
);
|
||||
MOCK_METHOD1(setAddressExtenesion, void(const std::string &));
|
||||
MOCK_CONST_METHOD2(sendPolicyVersion, Maybe<void>(const std::string &, const std::string &));
|
||||
};
|
||||
|
@ -1668,6 +1668,7 @@ private:
|
||||
|
||||
if (getAttribute("no-setting", "CROWDSEC_ENABLED") == "true") tags.insert(Tags::CROWDSEC);
|
||||
if (getAttribute("no-setting", "PLAYGROUND") == "true") tags.insert(Tags::PLAYGROUND);
|
||||
if (getAttribute("no-setting", "nginxproxymanager") == "true") tags.insert(Tags::NGINX_PROXY_MANAGER);
|
||||
|
||||
Report registration_report(
|
||||
"Local Agent Data",
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "log_generator.h"
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "customized_cereal_map.h"
|
||||
#include "declarative_policy_utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ReportIS;
|
||||
@ -745,6 +746,7 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
dbgDebug(D_ORCHESTRATOR) << "Policy file was not updated. Sending reload command regarding settings and data";
|
||||
auto signal_services = sendSignalForServices(nano_services_to_update, "");
|
||||
if (!signal_services.ok()) return signal_services.passErr();
|
||||
Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>()->turnOffApplyPolicyFlag();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
@ -888,6 +890,7 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
if (new_policy_path.compare(config_file_path) == 0) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Enforcing the default policy file";
|
||||
policy_version = version_value;
|
||||
Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>()->turnOffApplyPolicyFlag();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
@ -906,6 +909,7 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
}
|
||||
|
||||
if (!was_policy_updated && !send_signal_for_services_err.empty()) return genError(send_signal_for_services_err);
|
||||
Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>()->turnOffApplyPolicyFlag();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "service_controller.h"
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
#include "declarative_policy_utils.h"
|
||||
#include "mock/mock_orchestration_tools.h"
|
||||
#include "mock/mock_orchestration_status.h"
|
||||
#include "mock/mock_time_get.h"
|
||||
@ -158,10 +159,26 @@ public:
|
||||
return string_stream.str();
|
||||
}
|
||||
|
||||
void
|
||||
expectNewConfigRequest(const string &req_body, const string &response)
|
||||
{
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendSyncMessage(
|
||||
HTTPMethod::POST,
|
||||
"/set-new-configuration",
|
||||
req_body,
|
||||
_,
|
||||
_
|
||||
)
|
||||
).WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, response)));
|
||||
}
|
||||
|
||||
const uint16_t l4_firewall_service_port = 8888;
|
||||
const uint16_t waap_service_port = 7777;
|
||||
::Environment env;
|
||||
ConfigComponent config;
|
||||
DeclarativePolicyUtils declarative_policy_utils;
|
||||
string configuration_dir;
|
||||
string policy_extension;
|
||||
string settings_extension;
|
||||
@ -176,7 +193,7 @@ public:
|
||||
string services_port;
|
||||
StrictMock<MockTimeGet> time;
|
||||
StrictMock<MockRestApi> mock_rest_api;
|
||||
StrictMock<MockMessaging> mock_message;
|
||||
StrictMock<MockMessaging> mock_message;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
StrictMock<MockShellCmd> mock_shell_cmd;
|
||||
StrictMock<MockOrchestrationStatus> mock_orchestration_status;
|
||||
@ -254,6 +271,9 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersions(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -262,23 +282,7 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
|
||||
string general_settings_path = "/my/settings/path";
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_shell_cmd,
|
||||
@ -369,6 +373,9 @@ TEST_F(ServiceControllerTest, supportVersions)
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersions(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -377,23 +384,7 @@ TEST_F(ServiceControllerTest, supportVersions)
|
||||
string general_settings_path = "/my/settings/path";
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_shell_cmd,
|
||||
@ -464,6 +455,9 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -493,24 +487,7 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
|
||||
|
||||
string general_settings_path = "/my/settings/path";
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok());
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
|
||||
@ -585,6 +562,9 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -593,23 +573,7 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile)
|
||||
string general_settings_path = "/my/settings/path";
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_shell_cmd,
|
||||
@ -732,24 +696,11 @@ TEST_F(ServiceControllerTest, noPolicyUpdate)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_shell_cmd,
|
||||
@ -818,6 +769,9 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -835,24 +789,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
|
||||
|
||||
string general_settings_path = "/my/settings/path";
|
||||
string reply_msg1 = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg1)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg1);
|
||||
|
||||
// both policy and settings now being updated
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok());
|
||||
@ -871,26 +808,14 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
general_settings_path += "/new";
|
||||
|
||||
string reply_msg2 = "{\"id\": 2, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
Flags<MessageConnConfig> conn_flags2;
|
||||
conn_flags2.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 2,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags2,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillRepeatedly(Return(Maybe<string>(reply_msg2)));
|
||||
expectNewConfigRequest("{\n \"id\": 2,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg2);
|
||||
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok());
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
|
||||
@ -964,6 +889,9 @@ TEST_F(ServiceControllerTest, backup)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
|
||||
@ -988,21 +916,8 @@ TEST_F(ServiceControllerTest, backup)
|
||||
).WillRepeatedly(Return(string("registered and running")));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
"127.0.0.1",
|
||||
l4_firewall_service_port,
|
||||
_,
|
||||
"/set-new-configuration",
|
||||
_,
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
EXPECT_CALL(mock_message, sendSyncMessage(_, "/set-new-configuration", _, _, _))
|
||||
.WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, reply_msg)));
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
|
||||
@ -1077,6 +992,9 @@ TEST_F(ServiceControllerTest, backup_file_doesnt_exist)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
|
||||
@ -1103,21 +1021,7 @@ TEST_F(ServiceControllerTest, backup_file_doesnt_exist)
|
||||
).WillRepeatedly(Return(string("registered and running")));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
"127.0.0.1",
|
||||
l4_firewall_service_port,
|
||||
_,
|
||||
"/set-new-configuration",
|
||||
_,
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
|
||||
@ -1192,6 +1096,9 @@ TEST_F(ServiceControllerTest, backupAttempts)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
|
||||
@ -1218,21 +1125,7 @@ TEST_F(ServiceControllerTest, backupAttempts)
|
||||
).WillRepeatedly(Return(string("registered and running")));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
"127.0.0.1",
|
||||
l4_firewall_service_port,
|
||||
_,
|
||||
"/set-new-configuration",
|
||||
_,
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_CALL(mock_ml, yield(false)).Times(2);
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
@ -1316,6 +1209,9 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("orchestration", orchestration_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, writeFile(orchestration, orchestration_policy_path, false))
|
||||
@ -1336,23 +1232,7 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration)
|
||||
).WillRepeatedly(Return(string("registered and running")));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
|
||||
set<string> changed_policies = {
|
||||
@ -1389,6 +1269,9 @@ TEST_F(ServiceControllerTest, emptyServices)
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
|
||||
}
|
||||
|
||||
@ -1440,6 +1323,9 @@ TEST_F(ServiceControllerTest, failingWhileLoadingCurrentConfiguration)
|
||||
.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(err));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
|
||||
}
|
||||
|
||||
@ -1509,6 +1395,8 @@ TEST_F(ServiceControllerTest, failingWhileCopyingCurrentConfiguration)
|
||||
);
|
||||
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(old_configuration));
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
|
||||
@ -1578,6 +1466,9 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest)
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_TRUE(i_service_controller->isServiceInstalled("family1_id2"));
|
||||
@ -1672,6 +1563,8 @@ TEST_F(ServiceControllerTest, errorWhileWrtingNewConfiguration)
|
||||
);
|
||||
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(old_configuration));
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
|
||||
@ -1710,21 +1603,7 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles)
|
||||
EXPECT_CALL(tenant_manager, getInstances("tenant2", "1235")).WillOnce(Return(empty_ids));
|
||||
|
||||
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
_,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
_,
|
||||
string("/set-new-configuration"),
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
for(auto entry : tenant_files_input) {
|
||||
auto tenant = entry.first.first;
|
||||
@ -1801,6 +1680,9 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles)
|
||||
"l4_firewall", l4_firewall_policy_path_new, OrchestrationStatusConfigType::POLICY)
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::MD5, conf_file_name))
|
||||
.WillRepeatedly(Return(version_value));
|
||||
|
||||
string new_policy_file_path = "/etc/cp/conf/tenant_" + tenant + "_profile_" + profile + "/" + "policy.json";
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_file_path, new_policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
@ -1906,6 +1788,9 @@ 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, calculateChecksum(Package::ChecksumTypes::MD5, file_name))
|
||||
.WillOnce(Return(version_value));
|
||||
|
||||
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));
|
||||
@ -1934,23 +1819,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf)
|
||||
<< " \"error_message\": \"\""
|
||||
<< "}";
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
true,
|
||||
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
|
||||
I_Messaging::Method::POST,
|
||||
string("127.0.0.1"),
|
||||
l4_firewall_service_port,
|
||||
conn_flags,
|
||||
string("/set-new-configuration"),
|
||||
string(),
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).WillOnce(Return(Maybe<string>(reply_msg)));
|
||||
expectNewConfigRequest("{\n \"id\": 1,\n \"policy_version\": \"1.0.2,1.0.2\"\n}", reply_msg);
|
||||
|
||||
auto func = [&] (chrono::microseconds) { set_reconf_status->performRestCall(reconf_status); };
|
||||
EXPECT_CALL(mock_ml, yield(chrono::microseconds(2000000))).WillOnce(Invoke(func));
|
||||
|
2
components/security_apps/orchestration/update_communication/declarative_policy_utils.cc
Executable file → Normal file
2
components/security_apps/orchestration/update_communication/declarative_policy_utils.cc
Executable file → Normal file
@ -27,7 +27,7 @@ DeclarativePolicyUtils::init()
|
||||
auto mainloop = Singleton::Consume<I_MainLoop>::by<DeclarativePolicyUtils>();
|
||||
mainloop->addRecurringRoutine(
|
||||
I_MainLoop::RoutineType::Offline,
|
||||
chrono::minutes(1),
|
||||
chrono::seconds(30),
|
||||
[&] () { periodicPolicyLoad(); },
|
||||
"Automatic Policy Loading"
|
||||
);
|
||||
|
@ -32,7 +32,7 @@ void
|
||||
FogCommunication::init()
|
||||
{
|
||||
FogAuthenticator::init();
|
||||
declarative_policy_utils.init();
|
||||
i_declarative_policy = Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>();
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
@ -67,15 +67,15 @@ FogCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
Maybe<string> maybe_new_data = request.getData();
|
||||
string data_checksum = maybe_new_data.ok() ? maybe_new_data.unpack() : "";
|
||||
|
||||
if (declarative_policy_utils.shouldApplyPolicy()) {
|
||||
string policy_response = declarative_policy_utils.getUpdate(request);
|
||||
if (i_declarative_policy->shouldApplyPolicy()) {
|
||||
string policy_response = i_declarative_policy->getUpdate(request);
|
||||
if (!policy_response.empty()) {
|
||||
dbgTrace(D_ORCHESTRATOR) << "Apply policy - declarative mode";
|
||||
auto agent_details = Singleton::Consume<I_AgentDetails>::by<DeclarativePolicyUtils>();
|
||||
auto maybe_fog_address = agent_details->getFogDomain();
|
||||
string fog_address = maybe_fog_address.ok() ? maybe_fog_address.unpack() : "";
|
||||
|
||||
declarative_policy_utils.sendUpdatesToFog(
|
||||
i_declarative_policy->sendUpdatesToFog(
|
||||
unpacked_access_token,
|
||||
agent_details->getTenantId(),
|
||||
agent_details->getProfileId(),
|
||||
@ -83,7 +83,6 @@ FogCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
);
|
||||
}
|
||||
request = CheckUpdateRequest(manifest_checksum, policy_response, settings_checksum, data_checksum, "", "");
|
||||
declarative_policy_utils.turnOffApplyPolicyFlag();
|
||||
} else {
|
||||
request = CheckUpdateRequest(manifest_checksum, "", settings_checksum, data_checksum, "", "");
|
||||
}
|
||||
@ -103,7 +102,7 @@ FogCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
|
||||
string policy_mgmt_mode = getSettingWithDefault<string>("management", "profileManagedMode");
|
||||
if (policy_mgmt_mode == "declarative" && resourse_file.getFileName() =="policy") {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Download policy on declarative mode - returnig the local policy";
|
||||
return declarative_policy_utils.getCurrPolicy();
|
||||
return i_declarative_policy->getCurrPolicy();
|
||||
}
|
||||
static const string file_attribute_str = "/api/v2/agents/resources/";
|
||||
Maybe<string> attribute_file = Singleton::Consume<I_Messaging>::by<FogCommunication>()->downloadFile(
|
||||
|
@ -35,7 +35,7 @@ void
|
||||
HybridCommunication::init()
|
||||
{
|
||||
FogAuthenticator::init();
|
||||
declarative_policy_utils.init();
|
||||
i_declarative_policy = Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>();
|
||||
dbgTrace(D_ORCHESTRATOR) << "Initializing the Hybrid Communication Component";
|
||||
if (getConfigurationFlag("otp") != "") {
|
||||
otp = getConfigurationFlag("otp");
|
||||
@ -69,14 +69,14 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
dbgWarning(D_ORCHESTRATOR) << "Acccess Token not available.";
|
||||
}
|
||||
|
||||
if (!declarative_policy_utils.shouldApplyPolicy()) {
|
||||
if (!i_declarative_policy->shouldApplyPolicy()) {
|
||||
request = CheckUpdateRequest(manifest_checksum, "", "", "", "", "");
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "Getting policy update in Hybrid Communication";
|
||||
|
||||
string policy_response = declarative_policy_utils.getUpdate(request);
|
||||
string policy_response = i_declarative_policy->getUpdate(request);
|
||||
|
||||
auto env = Singleton::Consume<I_EnvDetails>::by<HybridCommunication>()->getEnvType();
|
||||
if (env == EnvType::K8S && !policy_response.empty()) {
|
||||
@ -123,7 +123,6 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
}
|
||||
|
||||
request = CheckUpdateRequest(manifest_checksum, policy_response, "", "", "", "");
|
||||
declarative_policy_utils.turnOffApplyPolicyFlag();
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
@ -136,7 +135,7 @@ HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
|
||||
<< resourse_file.getFileName();
|
||||
|
||||
if (resourse_file.getFileName() =="policy") {
|
||||
return declarative_policy_utils.getCurrPolicy();
|
||||
return i_declarative_policy->getCurrPolicy();
|
||||
}
|
||||
if (resourse_file.getFileName() == "manifest") {
|
||||
if (!access_token.ok()) return genError("Acccess Token not available.");
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
declarative_policy_utils.init();
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<UpdateCommunication>();
|
||||
rest->addRestCall<UpdateCommunication::Impl>(RestAction::SET, "orchestration-mode");
|
||||
setMode();
|
||||
@ -104,22 +105,17 @@ private:
|
||||
{
|
||||
if (getConfigurationFlag("orchestration-mode") == "offline_mode") {
|
||||
i_update_comm_impl = make_unique<LocalCommunication>();
|
||||
LocalCommunication *local_comm = static_cast<LocalCommunication*>(i_update_comm_impl.get());
|
||||
local_comm->init();
|
||||
return;
|
||||
} else if (getConfigurationFlag("orchestration-mode") == "hybrid_mode") {
|
||||
i_update_comm_impl = make_unique<HybridCommunication>();
|
||||
HybridCommunication *local_comm = static_cast<HybridCommunication*>(i_update_comm_impl.get());
|
||||
local_comm->init();
|
||||
return;
|
||||
} else {
|
||||
i_update_comm_impl = make_unique<FogCommunication>();
|
||||
}
|
||||
|
||||
i_update_comm_impl = make_unique<FogCommunication>();
|
||||
FogCommunication *fog_comm = static_cast<FogCommunication*>(i_update_comm_impl.get());
|
||||
fog_comm->init();
|
||||
i_update_comm_impl->init();
|
||||
}
|
||||
|
||||
std::unique_ptr<I_UpdateCommunication> i_update_comm_impl = nullptr;
|
||||
DeclarativePolicyUtils declarative_policy_utils;
|
||||
S2C_LABEL_PARAM(string, status, "status");
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,6 @@ link_directories(${BOOST_ROOT}/lib)
|
||||
|
||||
add_unit_test(
|
||||
update_communication_ut
|
||||
"local_communication_ut.cc"
|
||||
"local_communication_ut.cc;fog_communication_ut.cc"
|
||||
"rest;version;orchestration_modules;update_communication;singleton;config;metric;event_is;logging;agent_details;-lboost_regex;local_policy_mgmt_gen;connkey;"
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
#add_subdirectory(cptest)
|
||||
add_subdirectory(cptest)
|
||||
add_subdirectory(agent_core_utilities)
|
||||
add_subdirectory(shell_cmd)
|
||||
add_subdirectory(debug_is)
|
||||
|
@ -66,6 +66,8 @@ enum class Tags {
|
||||
CROWDSEC,
|
||||
PLAYGROUND,
|
||||
API_DISCOVERY,
|
||||
NGINX_PROXY_MANAGER,
|
||||
WEB_SERVER_APISIX,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
@ -108,7 +108,9 @@ TagAndEnumManagement::convertStringToTag(const string &tag)
|
||||
{"Horizon Telemetry Metrics", ReportIS::Tags::HORIZON_TELEMETRY_METRICS},
|
||||
{"Crowdsec", ReportIS::Tags::CROWDSEC},
|
||||
{"apiDiscoveryCloudMessaging", ReportIS::Tags::API_DISCOVERY},
|
||||
{"Playground", ReportIS::Tags::PLAYGROUND}
|
||||
{"Playground", ReportIS::Tags::PLAYGROUND},
|
||||
{"Nginx Proxy Manager", ReportIS::Tags::NGINX_PROXY_MANAGER},
|
||||
{"APISIX Server", ReportIS::Tags::WEB_SERVER_APISIX}
|
||||
};
|
||||
|
||||
auto report_is_tag = strings_to_tags.find(tag);
|
||||
@ -314,7 +316,9 @@ EnumArray<Tags, string> TagAndEnumManagement::tags_translation_arr {
|
||||
"Horizon Telemetry Metrics",
|
||||
"Crowdsec",
|
||||
"Playground",
|
||||
"apiDiscoveryCloudMessaging"
|
||||
"apiDiscoveryCloudMessaging",
|
||||
"Nginx Proxy Manager",
|
||||
"APISIX Server"
|
||||
};
|
||||
|
||||
EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation {
|
||||
|
@ -5,6 +5,10 @@ install(FILES cp-nano-http-transaction-handler-debug-conf.json DESTINATION http_
|
||||
install(FILES cp-nano-http-transaction-handler.cfg DESTINATION http_transaction_handler_service/conf PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
install(FILES k8s-log-file-handler.sh DESTINATION http_transaction_handler_service/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
|
||||
install(DIRECTORY snort3_to_ips/ DESTINATION http_transaction_handler_service/scripts/snort3_to_ips FILES_MATCHING PATTERN "*" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(FILES snort_to_ips_local.py DESTINATION http_transaction_handler_service/scripts PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
install(FILES exception.py DESTINATION http_transaction_handler_service/scripts PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
|
||||
#install(DIRECTORY ${ng_module_osrc_pcre2_path}/lib/ DESTINATION http_transaction_handler_service/lib/ FILES_MATCHING PATTERN "libpcre2-8.so*" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
#install(DIRECTORY ${ng_module_osrc_pcre2_path}/lib/ DESTINATION http_transaction_handler_service/lib/ FILES_MATCHING PATTERN "libpcre2-posix.so*" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
#install(RUNTIME_DEPENDENCY_SET xml DESTINATION http_transaction_handler_service/lib/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||
|
8
nodes/http_transaction_handler/package/exception.py
Executable file
8
nodes/http_transaction_handler/package/exception.py
Executable file
@ -0,0 +1,8 @@
|
||||
class SnortHookException(Exception):
|
||||
|
||||
def __init__(self, message="", practice_id=""):
|
||||
self.message = message
|
||||
self.practice_id = practice_id
|
||||
|
||||
def __str__(self):
|
||||
return "{}".format(self.message)
|
@ -7,6 +7,7 @@ INSTALLATION_TIME=$(date)
|
||||
|
||||
WAAP_POLICY_FOLDER_PATH=/etc/cp/conf/waap
|
||||
IPS_POLICY_FOLDER_PATH=/etc/cp/conf/ips
|
||||
SNORT_SCRIPTS_PATH=/etc/cp/scripts/
|
||||
|
||||
DEFAULT_HTTP_TRANSACTION_HANDLER_EVENT_BUFFER=/var/log/nano_agent/event_buffer/HTTP_TRANSACTION_HANDLER_events
|
||||
|
||||
@ -216,6 +217,10 @@ run_installation()
|
||||
install_policy $is_debug_mode "$var_certs_dir"
|
||||
install_waap
|
||||
|
||||
cp_exec "cp -fr scripts/snort3_to_ips $SNORT_SCRIPTS_PATH/snort3_to_ips"
|
||||
cp_exec "cp -f scripts/exception.py $SNORT_SCRIPTS_PATH/exception.py"
|
||||
cp_exec "cp -f scripts/snort_to_ips_local.py $SNORT_SCRIPTS_PATH/snort_to_ips_local.py"
|
||||
|
||||
${INSTALL_COMMAND} lib/libshmem_ipc.so /usr/lib/cpnano/
|
||||
${INSTALL_COMMAND} lib/libcompression_utils.so /usr/lib/
|
||||
cp_exec "ldconfig"
|
||||
|
@ -0,0 +1,53 @@
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class DetectionRules:
|
||||
|
||||
def __init__(self):
|
||||
self.data = {
|
||||
"type": "simple",
|
||||
"SSM": "",
|
||||
"keywords": "",
|
||||
"context": []
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
if self.data["context"] and (len(self.data["keywords"]) or len(self.data["SSM"])):
|
||||
pass
|
||||
else:
|
||||
raise SnortHookException("No detection rule in the rule")
|
||||
|
||||
def set_default_if_needed(self):
|
||||
pass
|
||||
|
||||
def is_key_valid(self, key):
|
||||
if key in self.data.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
def parse_data(self, key, value):
|
||||
self.parse_func_map[key](self, value)
|
||||
|
||||
def parse_keywords_data(self, value):
|
||||
if len(self.data["keywords"]) != 0:
|
||||
self.data["keywords"] += " "
|
||||
self.data["keywords"] += value
|
||||
|
||||
def parse_context_data(self, value):
|
||||
if value not in self.data["context"]:
|
||||
self.data["context"].append(value)
|
||||
|
||||
def parse_ssm_data(self, value):
|
||||
if self.data["SSM"] != "":
|
||||
raise SnortHookException("two fast_pattern content")
|
||||
self.data["SSM"] += value
|
||||
|
||||
def parse_type_data(self, value):
|
||||
raise SnortHookException("DetectionRules of type not implemented")
|
||||
|
||||
parse_func_map = {
|
||||
"type": parse_type_data,
|
||||
"SSM": parse_ssm_data,
|
||||
"keywords": parse_keywords_data,
|
||||
"context": parse_context_data
|
||||
}
|
91
nodes/http_transaction_handler/package/snort3_to_ips/Signature/IpsKW.py
Executable file
91
nodes/http_transaction_handler/package/snort3_to_ips/Signature/IpsKW.py
Executable file
@ -0,0 +1,91 @@
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class IpsKW:
|
||||
|
||||
def __init__(self, keyword, value, optional_modifier):
|
||||
self.keyword = keyword
|
||||
self.value = value
|
||||
self.optional_modifiers = optional_modifier
|
||||
|
||||
def construct(self):
|
||||
return self.construct_func_map[self.keyword](self)
|
||||
|
||||
def construct_name(self):
|
||||
return [("protectionName", self.value)]
|
||||
|
||||
def construct_detection_keyword(self):
|
||||
constructed_data = []
|
||||
optional_modifier_str = ""
|
||||
for key in self.optional_modifiers:
|
||||
if key in ['nocase', 'relative']:
|
||||
optional_modifier_str += ", " + key
|
||||
elif key == 'depth':
|
||||
optional_modifier_str += ", {} {}".format(key, self.optional_modifiers[key])
|
||||
elif key == 'offset':
|
||||
if self.optional_modifiers[key] == 0:
|
||||
continue
|
||||
optional_modifier_str += ", {} {}".format(key, self.optional_modifiers[key])
|
||||
elif key == 'part':
|
||||
optional_modifier_str += ", {} {}".format(key, self.optional_modifiers[key])
|
||||
constructed_data.append(("context", self.optional_modifiers[key]))
|
||||
else:
|
||||
raise SnortHookException("Error: Key '{}' is not supported in keywords".format(key))
|
||||
constructed_data.append(("keywords", "data: {}{};".format(self.value, optional_modifier_str)))
|
||||
return constructed_data
|
||||
|
||||
def construct_pcre(self):
|
||||
constructed_data = []
|
||||
optional_modifier_str = ""
|
||||
for key in self.optional_modifiers:
|
||||
if key in ['nocase', 'relative']:
|
||||
optional_modifier_str += ", " + key
|
||||
elif key in ['offset']:
|
||||
if self.optional_modifiers[key] == 0:
|
||||
continue
|
||||
optional_modifier_str += ", {} {}".format(key, self.optional_modifiers[key])
|
||||
elif key == 'part':
|
||||
optional_modifier_str += ", {} {}".format(key, self.optional_modifiers[key])
|
||||
constructed_data.append(("context", self.optional_modifiers[key]))
|
||||
else:
|
||||
raise SnortHookException("Error: Key {} is not supported in pcre".format(key))
|
||||
constructed_data.append(("keywords", "pcre: {}{};".format(self.value, optional_modifier_str)))
|
||||
return constructed_data
|
||||
|
||||
def construct_SSM_keyword(self):
|
||||
constructed_data = []
|
||||
for key in self.optional_modifiers:
|
||||
if key == 'part':
|
||||
constructed_data.append(("context", self.optional_modifiers[key]))
|
||||
constructed_data.append(("SSM", self.value.strip("\"")))
|
||||
|
||||
return constructed_data
|
||||
|
||||
def construct_length_keyword(self):
|
||||
return [("keywords", "{}: {}, {}, part {};".format(self.keyword, self.optional_modifiers['var'],
|
||||
self.value, self.optional_modifiers['part']))]
|
||||
|
||||
def construct_cvelist(self):
|
||||
return [(self.keyword, self.value)]
|
||||
|
||||
def construct_severity(self):
|
||||
return [(self.keyword, self.value)]
|
||||
|
||||
def construct_tags(self):
|
||||
return [(self.keyword, "Vul_Type_{}".format(self.value))]
|
||||
|
||||
def construct_sid_rev(self):
|
||||
return [("maintrainId", "{}:{}".format(self.keyword, self.value))]
|
||||
|
||||
construct_func_map = {
|
||||
'protectionName': construct_name,
|
||||
'keywords': construct_detection_keyword,
|
||||
'length': construct_length_keyword,
|
||||
'SSM': construct_SSM_keyword,
|
||||
'tags': construct_tags,
|
||||
'pcre': construct_pcre,
|
||||
'cveList': construct_cvelist,
|
||||
'severity': construct_severity,
|
||||
'sid': construct_sid_rev,
|
||||
'rev': construct_sid_rev
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
from snort3_to_ips.Signature.ProtectionMetadata import ProtectionMetadata
|
||||
from snort3_to_ips.Signature.DetectionRules import DetectionRules
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class IpsSignature:
|
||||
def __init__(self):
|
||||
self.protectionMetadata = ProtectionMetadata()
|
||||
self.detectionRules = DetectionRules()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.output_signature())
|
||||
|
||||
def parse_data(self, constructs):
|
||||
for json_key, json_value in constructs:
|
||||
if self.protectionMetadata.is_key_valid(json_key):
|
||||
self.protectionMetadata.parse_data(json_key, json_value)
|
||||
elif self.detectionRules.is_key_valid(json_key):
|
||||
self.detectionRules.parse_data(json_key, json_value)
|
||||
else:
|
||||
raise SnortHookException("'{}' is not a valid keyword in snort signature".format(json_key))
|
||||
|
||||
def validate(self):
|
||||
self.protectionMetadata.validate()
|
||||
self.detectionRules.validate()
|
||||
|
||||
def set_default_if_needed(self):
|
||||
self.protectionMetadata.set_default_if_needed()
|
||||
self.detectionRules.set_default_if_needed()
|
||||
|
||||
def output_signature(self):
|
||||
self.validate()
|
||||
self.set_default_if_needed()
|
||||
return {"protectionMetadata": self.protectionMetadata.data, "detectionRules": self.detectionRules.data}
|
@ -0,0 +1,70 @@
|
||||
class ProtectionMetadata:
|
||||
|
||||
def __init__(self):
|
||||
self.data = {
|
||||
"protectionName": "",
|
||||
"severity": "",
|
||||
"confidenceLevel": "",
|
||||
"performanceImpact": "",
|
||||
"lastUpdate": "",
|
||||
"maintrainId": "",
|
||||
"tags": ["Snort"],
|
||||
"cveList": [],
|
||||
"silent": False
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
if len(self.data["protectionName"]) == 0:
|
||||
raise Exception("msg field missing in the snort rule")
|
||||
|
||||
def set_default_if_needed(self):
|
||||
if self.data["severity"] == "":
|
||||
self.data["severity"] = "Critical"
|
||||
if self.data["confidenceLevel"] == "":
|
||||
self.data["confidenceLevel"] = "High"
|
||||
if self.data["performanceImpact"] == "":
|
||||
self.data["performanceImpact"] = "Medium"
|
||||
if self.data["lastUpdate"] == "":
|
||||
self.data["lastUpdate"] = "20210909"
|
||||
|
||||
def is_key_valid(self, key):
|
||||
if key in self.data.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
def parse_data(self, key, value):
|
||||
self.parse_func_map[key](self, key, value)
|
||||
|
||||
def parse_name_data(self, key, value):
|
||||
self.data[key] = value
|
||||
|
||||
def parse_cvelist(self, key, value):
|
||||
if value not in self.data[key]:
|
||||
self.data[key].append(value)
|
||||
|
||||
def parse_severity(self, key, value):
|
||||
self.data[key] = value
|
||||
|
||||
def parse_main_train_id(self, key, value):
|
||||
if self.data[key] != "":
|
||||
self.data[key] += " "
|
||||
self.data[key] += value
|
||||
|
||||
def parse_tags(self, key, value):
|
||||
if value not in self.data[key]:
|
||||
self.data[key].append(value)
|
||||
|
||||
def not_implemented(self, key, value):
|
||||
print("Not implemented for key {} with value {}".format(key, value))
|
||||
|
||||
parse_func_map = {
|
||||
"protectionName": parse_name_data,
|
||||
"severity": parse_severity,
|
||||
"confidenceLevel": not_implemented,
|
||||
"performanceImpact": not_implemented,
|
||||
"lastUpdate": not_implemented,
|
||||
"maintrainId": parse_main_train_id,
|
||||
"tags": parse_tags,
|
||||
"cveList": parse_cvelist,
|
||||
"silent": not_implemented,
|
||||
}
|
49
nodes/http_transaction_handler/package/snort3_to_ips/Signature/Signatures.py
Executable file
49
nodes/http_transaction_handler/package/snort3_to_ips/Signature/Signatures.py
Executable file
@ -0,0 +1,49 @@
|
||||
import json
|
||||
|
||||
from snort3_to_ips.SnortRule.SnortRule import SnortRule
|
||||
from snort3_to_ips.utils.utils import parse_snort_rules_line, is_invalid_line
|
||||
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class Signatures:
|
||||
def __init__(self):
|
||||
self.signatures = []
|
||||
self.error_rules = []
|
||||
self.error_internal = []
|
||||
|
||||
def load_snort_signatures(self, rules_input):
|
||||
line_number = 0
|
||||
for line in rules_input.split("\n"):
|
||||
line_number += 1
|
||||
if is_invalid_line(line):
|
||||
continue
|
||||
rule = line.strip()
|
||||
header, body = parse_snort_rules_line(rule)
|
||||
try:
|
||||
snort_rule = SnortRule(header)
|
||||
if not snort_rule.is_http_rule(body):
|
||||
continue
|
||||
snort_rule.parse_body(body)
|
||||
self.signatures.append(snort_rule.convert())
|
||||
except SnortHookException as se:
|
||||
self.error_rules.append({"Error": str(se), "Line": line_number})
|
||||
except Exception as e:
|
||||
self.error_internal.append({"Error": str(e), "Line": line_number})
|
||||
|
||||
def reset(self):
|
||||
self.signatures = []
|
||||
self.error_rules = []
|
||||
|
||||
def output_errors(self, output_pf):
|
||||
output = {"Errors": self.error_rules}
|
||||
with open(output_pf, 'w') as f:
|
||||
json.dump(output, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def output_ips_signature_package(self, output_pf):
|
||||
output = {"IPSSnortSigs": {"protections": self.signatures}}
|
||||
with open(output_pf, 'w') as f:
|
||||
json.dump(output, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def get_payload_data(self):
|
||||
return self.signatures, self.error_rules, self.error_internal
|
190
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortKW.py
Executable file
190
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortKW.py
Executable file
@ -0,0 +1,190 @@
|
||||
from snort3_to_ips.Signature.IpsKW import IpsKW
|
||||
from snort3_to_ips.utils.utils import is_hex_segment_in_str
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class SnortKW:
|
||||
|
||||
def __init__(self, keyword, value, optional_modifiers):
|
||||
self.keyword = keyword
|
||||
self.value = value
|
||||
self.optional_modifiers = optional_modifiers
|
||||
|
||||
def convert(self, snort_rule):
|
||||
return self.convert_func_map[self.keyword](self, snort_rule)
|
||||
|
||||
def convert_snort_content_kw(self, snort_rule):
|
||||
ips_data_modifiers = self.get_ips_modifiers_from_rule(snort_rule)
|
||||
if ips_data_modifiers.pop('fast_pattern', False) and not is_hex_segment_in_str(self.value):
|
||||
return [IpsKW("SSM", self.value, ips_data_modifiers)]
|
||||
return [IpsKW("keywords", self.value, ips_data_modifiers)]
|
||||
|
||||
def convert_snort_pcre_kw(self, snort_rule):
|
||||
ips_data_modifiers = snort_rule.get_ips_context()
|
||||
return [IpsKW("pcre", self.value, ips_data_modifiers)]
|
||||
|
||||
def convert_snort_flow_kw(self, snort_rule):
|
||||
for modifier in self.optional_modifiers:
|
||||
if modifier == "to_server" or modifier == "from_client":
|
||||
snort_rule.flow = "client_to_server"
|
||||
elif modifier == "to_client" or modifier == "from_server":
|
||||
snort_rule.flow = "server_to_client"
|
||||
elif modifier in ["established", "not_established", "stateless"]:
|
||||
pass
|
||||
elif modifier in ["no_stream", "only_stream"]:
|
||||
pass
|
||||
elif modifier in ["no_frag", "only_frag"]:
|
||||
pass
|
||||
else:
|
||||
raise SnortHookException("unsupported modifier for '{}': '{}'".format(self.keyword, modifier))
|
||||
return []
|
||||
|
||||
def convert_snort_msg_kw(self, snort_rule):
|
||||
return [IpsKW("protectionName", self.value.strip("\""), "")]
|
||||
|
||||
def convert_snort_sticky_buffer(self, snort_rule):
|
||||
snort_rule.sticky_buffer = self.keyword
|
||||
if self.value != "":
|
||||
if self.keyword != "http_header":
|
||||
raise SnortHookException("arguments are not supported for '{}' of value '{}'".format(self.keyword, self.value))
|
||||
if self.value == "field":
|
||||
snort_rule.dynamic_buffer = self.optional_modifiers
|
||||
else:
|
||||
raise SnortHookException("Unknown argument for '{}', '{}'".format(self.keyword, self.value))
|
||||
return []
|
||||
|
||||
def convert_snort_reference(self, snort_rule):
|
||||
if self.value == 'bugtraq':
|
||||
return [IpsKW("cveList", "BUGTRAQ-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'cve':
|
||||
return [IpsKW("cveList", "CVE-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'nessus':
|
||||
return [IpsKW("cveList", "NESSUS-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'arachnids':
|
||||
return [IpsKW("cveList", "ARACHNIDS-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'mcafee':
|
||||
return [IpsKW("cveList", "MCAFEE-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'osvdb':
|
||||
return [IpsKW("cveList", "OSVDB-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'msb':
|
||||
return [IpsKW("cveList", "MSB-{}".format(self.optional_modifiers[self.value]), "")]
|
||||
elif self.value == 'url':
|
||||
return [IpsKW("cveList", "http://{}".format(self.optional_modifiers[self.value]), "")]
|
||||
else:
|
||||
raise SnortHookException("Unknown system in Reference of value: {}".format(self.value))
|
||||
|
||||
def convert_snort_classtype(self, snort_rule):
|
||||
return [IpsKW("severity", self.optional_modifiers[self.value], ""),
|
||||
IpsKW("tags", self.value.replace("-", " ").title().replace(" ", "_"), "")]
|
||||
|
||||
def convert_snort_priority(self, snort_rule):
|
||||
return [IpsKW("severity", self.value, "")]
|
||||
|
||||
def convert_snort_bufferlen_kw(self, snort_rule):
|
||||
ips_kw_list = []
|
||||
ips_data_modifiers = snort_rule.get_ips_context()
|
||||
if "<=>" in self.value:
|
||||
left_var, right_var = self.value.split("<=>")
|
||||
if not left_var.isnumeric() or not right_var.isnumeric():
|
||||
raise SnortHookException("bufferlen - illegal numerical value")
|
||||
ips_data_modifiers['var'] = left_var
|
||||
ips_kw_list.append(IpsKW("length", "min", ips_data_modifiers))
|
||||
ips_data_modifiers = snort_rule.get_ips_context()
|
||||
ips_data_modifiers['var'] = right_var
|
||||
ips_kw_list.append(IpsKW("length", "max", ips_data_modifiers))
|
||||
elif "<>" in self.value:
|
||||
left_var, right_var = self.value.split("<>")
|
||||
ips_data_modifiers['var'] = left_var
|
||||
if not left_var.isnumeric() or not right_var.isnumeric():
|
||||
raise SnortHookException("bufferlen - illegal numerical value")
|
||||
ips_kw_list.append(IpsKW("length", "min", ips_data_modifiers))
|
||||
ips_data_modifiers = snort_rule.get_ips_context()
|
||||
ips_data_modifiers['var'] = right_var
|
||||
ips_kw_list.append(IpsKW("length", "max", ips_data_modifiers))
|
||||
elif "<" in self.value:
|
||||
if not self.value.split("<")[1].isnumeric():
|
||||
raise SnortHookException("bufferlen - illegal numerical value")
|
||||
ips_data_modifiers['var'] = self.value.split("<")[1]
|
||||
ips_kw_list.append(IpsKW("length", "max", ips_data_modifiers))
|
||||
elif ">" in self.value:
|
||||
ips_data_modifiers['var'] = self.value.split(">")[1]
|
||||
if not self.value.split(">")[1].isnumeric():
|
||||
raise SnortHookException("bufferlen - illegal numerical value")
|
||||
ips_kw_list.append(IpsKW("length", "min", ips_data_modifiers))
|
||||
elif self.value.isnumeric():
|
||||
ips_data_modifiers['var'] = self.value
|
||||
ips_kw_list.append(IpsKW("length", "exact", ips_data_modifiers))
|
||||
else:
|
||||
raise SnortHookException("bufferlen operator is illegal")
|
||||
return ips_kw_list
|
||||
|
||||
def convert_sid_kw(self, snort_rule):
|
||||
return [IpsKW("sid", self.value, "")]
|
||||
|
||||
def convert_rev_kw(self, snort_rule):
|
||||
return [IpsKW("rev", self.value, "")]
|
||||
|
||||
def not_implemented(self, snort_rule):
|
||||
return []
|
||||
|
||||
convert_func_map = {
|
||||
# Primarily functions
|
||||
'content': convert_snort_content_kw,
|
||||
'pcre': convert_snort_pcre_kw,
|
||||
'bufferlen': convert_snort_bufferlen_kw,
|
||||
'flow': convert_snort_flow_kw,
|
||||
# metadata functions
|
||||
'msg': convert_snort_msg_kw,
|
||||
'reference': convert_snort_reference,
|
||||
'gid': not_implemented,
|
||||
'sid': convert_sid_kw,
|
||||
'rev': convert_rev_kw,
|
||||
'classtype': convert_snort_classtype,
|
||||
'priority': convert_snort_priority,
|
||||
'metadata': not_implemented,
|
||||
# http functions
|
||||
'pkt_data': convert_snort_sticky_buffer,
|
||||
'http_uri': convert_snort_sticky_buffer,
|
||||
'http_raw_uri': convert_snort_sticky_buffer,
|
||||
'http_header': convert_snort_sticky_buffer,
|
||||
'http_raw_header': convert_snort_sticky_buffer,
|
||||
'http_method': convert_snort_sticky_buffer,
|
||||
'http_client_body': convert_snort_sticky_buffer,
|
||||
'http_cookie': convert_snort_sticky_buffer,
|
||||
'http_raw_cookie': convert_snort_sticky_buffer,
|
||||
'http_stat_code': convert_snort_sticky_buffer,
|
||||
'http_stat_msg': convert_snort_sticky_buffer,
|
||||
'http_encode': convert_snort_sticky_buffer,
|
||||
# backward compatibility rules.
|
||||
'service': not_implemented
|
||||
}
|
||||
|
||||
def get_ips_modifiers_from_rule(self, snort_rule):
|
||||
|
||||
ips_data_modifiers = {}
|
||||
|
||||
for rule in self.optional_modifiers:
|
||||
if rule == 'nocase':
|
||||
ips_data_modifiers['nocase'] = self.optional_modifiers['nocase']
|
||||
elif rule == 'depth':
|
||||
ips_data_modifiers['depth'] = self.optional_modifiers['depth']
|
||||
elif rule == 'distance':
|
||||
if int(self.optional_modifiers['distance']) != 0:
|
||||
ips_data_modifiers['offset'] = self.optional_modifiers['distance']
|
||||
ips_data_modifiers['relative'] = True
|
||||
elif rule == 'offset':
|
||||
if int(self.optional_modifiers['offset']) != 0:
|
||||
ips_data_modifiers['offset'] = self.optional_modifiers['offset']
|
||||
elif rule == 'within':
|
||||
ips_data_modifiers['depth'] = self.optional_modifiers['within']
|
||||
ips_data_modifiers['relative'] = True
|
||||
elif rule == 'fast_pattern':
|
||||
ips_data_modifiers['fast_pattern'] = True
|
||||
else:
|
||||
# print("Error: Not supported convert from {}".format(rule))
|
||||
raise SnortHookException("For keyword '{}', unsupported modifier '{}'".format(self.keyword, rule))
|
||||
|
||||
ips_data_modifiers.update(snort_rule.get_ips_context())
|
||||
|
||||
return ips_data_modifiers
|
||||
|
206
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortKWParser.py
Executable file
206
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortKWParser.py
Executable file
@ -0,0 +1,206 @@
|
||||
from exception import SnortHookException
|
||||
|
||||
class SnortKWParser:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def parse_kw_parameters(self, snort_rule):
|
||||
tmp_split = snort_rule.split(":")
|
||||
keyword = tmp_split[0]
|
||||
return self.parse_func_map[keyword](self, snort_rule)
|
||||
|
||||
def simple_rule(self, snort_rule):
|
||||
return snort_rule.strip(), "", {}
|
||||
|
||||
def simple_binary_rule(self, snort_rule):
|
||||
keyword, value = snort_rule.split(":")
|
||||
return keyword, value, {}
|
||||
|
||||
def parse_content(self, snort_rule):
|
||||
tmp_split = snort_rule.split(":", 1)
|
||||
keyword = tmp_split[0]
|
||||
|
||||
value = tmp_split[1][:tmp_split[1].find("\"", 2) + 1].strip()
|
||||
optional_string = tmp_split[1][tmp_split[1].find("\"", 2) + 1:].strip(",").strip()
|
||||
|
||||
if optional_string == "":
|
||||
return keyword, value, {}
|
||||
|
||||
optional_modifiers = {}
|
||||
for optional_command in optional_string.split(","):
|
||||
optional_command = optional_command.strip()
|
||||
command = optional_command.strip().split(" ", 1)
|
||||
if len(command) == 1:
|
||||
optional_modifiers[command[0]] = True
|
||||
else:
|
||||
optional_modifiers[command[0]] = command[1]
|
||||
return keyword, value, optional_modifiers
|
||||
|
||||
def parse_pcre(self, snort_rule):
|
||||
tmp_split = snort_rule.split(":", 1)
|
||||
keyword = tmp_split[0]
|
||||
|
||||
value = tmp_split[1][:tmp_split[1].rfind("\"", 2) + 1].strip()
|
||||
optional_string = tmp_split[1][tmp_split[1].rfind("/", 1) + 1:tmp_split[1].rfind("\"", 1)].strip()
|
||||
optional_modifiers = {}
|
||||
|
||||
for modifier in optional_string:
|
||||
if modifier in 'ismxGARE':
|
||||
pass
|
||||
elif modifier in 'O':
|
||||
raise SnortHookException("unsupported {} modifier {}".format(keyword, modifier))
|
||||
else:
|
||||
raise SnortHookException("Unknown {} modifier {}".format(keyword, modifier))
|
||||
|
||||
return keyword, value, optional_modifiers
|
||||
|
||||
def parse_reference(self, snort_rule):
|
||||
keyword = snort_rule.split(":")[0]
|
||||
value = snort_rule.split(":")[1].split(",")[0]
|
||||
optional_modifiers = {value: snort_rule.split(":")[1].split(",")[1]}
|
||||
return keyword, value, optional_modifiers
|
||||
|
||||
def parse_classtype(self, snort_rule):
|
||||
keyword = snort_rule.split(":")[0]
|
||||
value = snort_rule.split(":")[1].strip()
|
||||
optional_modifiers = {value: self.snort_default_classifications[value]}
|
||||
return keyword, value, optional_modifiers
|
||||
|
||||
def parse_priority(self, snort_rule):
|
||||
keyword = snort_rule.split(":")[0]
|
||||
value = int(snort_rule.split(":")[1].strip())
|
||||
if value > 4:
|
||||
value = 4
|
||||
return keyword, self.priority_map[value], {}
|
||||
|
||||
def parse_sticky_buffer(self, snort_rule):
|
||||
split_rule = snort_rule.split(":", 1)
|
||||
if len(split_rule) == 2:
|
||||
arguments_split = split_rule[1].split(" ")
|
||||
return split_rule[0], arguments_split[0].strip(), {arguments_split[0].strip(): arguments_split[1].strip()}
|
||||
return snort_rule.strip(), "", {}
|
||||
|
||||
def parse_metadata(self, snort_rule):
|
||||
keyword, value = snort_rule.split(":")
|
||||
optional_modifiers = {}
|
||||
for metadata in value.split(","):
|
||||
key, value = metadata.strip().split(" ", 1)
|
||||
if key not in optional_modifiers.keys():
|
||||
optional_modifiers[key] = set()
|
||||
optional_modifiers[key].add(value)
|
||||
return keyword, "", optional_modifiers
|
||||
|
||||
def parse_flow(self, snort_rule):
|
||||
keyword, value = snort_rule.split(":")
|
||||
optional_modifiers = []
|
||||
for modifier in value.split(','):
|
||||
optional_modifiers.append(modifier.strip())
|
||||
return keyword, value, optional_modifiers
|
||||
|
||||
def parse_service(self, snort_rule):
|
||||
keyword, value = snort_rule.split(":")
|
||||
return keyword, value, {}
|
||||
|
||||
def not_implemented(self, snort_rule):
|
||||
raise SnortHookException("unsupported keyword '{}'".format(snort_rule.split(":")[0]))
|
||||
|
||||
parse_func_map = {
|
||||
# Primarily functions
|
||||
'content': parse_content,
|
||||
'pcre': parse_pcre,
|
||||
'flow': parse_flow,
|
||||
'bufferlen': simple_binary_rule,
|
||||
# metadata functions
|
||||
'msg': simple_binary_rule,
|
||||
'reference': parse_reference,
|
||||
'gid': simple_binary_rule,
|
||||
'sid': simple_binary_rule,
|
||||
'rev': simple_binary_rule,
|
||||
'classtype': parse_classtype,
|
||||
'priority': parse_priority,
|
||||
'metadata': parse_metadata,
|
||||
# http functions
|
||||
'pkt_data': simple_rule,
|
||||
'http_uri': parse_sticky_buffer,
|
||||
'http_raw_uri': parse_sticky_buffer,
|
||||
'http_header': parse_sticky_buffer,
|
||||
'http_raw_header': parse_sticky_buffer,
|
||||
'http_method': parse_sticky_buffer,
|
||||
'http_client_body': parse_sticky_buffer,
|
||||
'http_cookie': parse_sticky_buffer,
|
||||
'http_stat_code': parse_sticky_buffer,
|
||||
'http_stat_msg': parse_sticky_buffer,
|
||||
'http_raw_cookie': parse_sticky_buffer,
|
||||
# Snort 2 functions
|
||||
'service': parse_service,
|
||||
# Not implemented
|
||||
'byte_test': not_implemented,
|
||||
'file_data': not_implemented,
|
||||
'byte_jump': not_implemented,
|
||||
'isdataat': not_implemented,
|
||||
'dsize': not_implemented,
|
||||
'icode': not_implemented,
|
||||
'flowbits': not_implemented,
|
||||
'itype': not_implemented,
|
||||
'dce_iface': not_implemented,
|
||||
'cmp_id': not_implemented,
|
||||
'detection_filter': not_implemented,
|
||||
'flags': not_implemented,
|
||||
'sip_stat_code': not_implemented,
|
||||
'ack': not_implemented,
|
||||
'ip_proto': not_implemented,
|
||||
'sip_method': not_implemented,
|
||||
'asn1': not_implemented,
|
||||
'ssl_version': not_implemented,
|
||||
'base64_decode': not_implemented,
|
||||
'ssl_state': not_implemented,
|
||||
'sip_header': not_implemented,
|
||||
'fragbits': not_implemented,
|
||||
}
|
||||
|
||||
priority_map = {
|
||||
1: "High",
|
||||
2: "Medium",
|
||||
3: "Low",
|
||||
4: "Very Low"
|
||||
}
|
||||
|
||||
# Default snort classification for reference.
|
||||
# If needed custom config, we should provide it. (1 being High, 2 Medium, 3 Low, 4 Very Low)
|
||||
snort_default_classifications = {
|
||||
"attempted-admin": "High",
|
||||
"attempted-user": "High",
|
||||
"inappropriate-content": "High",
|
||||
"policy-violation": "High",
|
||||
"shellcode-detect": "High",
|
||||
"successful-admin": "High",
|
||||
"successful-user": "High",
|
||||
"trojan-activity": "High",
|
||||
"unsuccessful-user": "High",
|
||||
"web-application-attack": "High",
|
||||
"attempted-dos": "Medium",
|
||||
"attempted-recon": "Medium",
|
||||
"bad-unknown": "Medium",
|
||||
"default-login-attempt": "Medium",
|
||||
"denial-of-service": "Medium",
|
||||
"misc-attack": "Medium",
|
||||
"non-standard-protocol": "Medium",
|
||||
"rpc-portmap-decode": "Medium",
|
||||
"successful-dos": "Medium",
|
||||
"successful-recon-largescale": "Medium",
|
||||
"successful-recon-limited": "Medium",
|
||||
"suspicious-filename-detect": "Medium",
|
||||
"suspicious-login": "Medium",
|
||||
"system-call-detect": "Medium",
|
||||
"unusual-client-port-connection": "Medium",
|
||||
"web-application-activity": "Medium",
|
||||
"icmp-event": "Low",
|
||||
"misc-activity": "Low",
|
||||
"network-scan": "Low",
|
||||
"not-suspicious": "Low",
|
||||
"protocol-command-decode": "Low",
|
||||
"string-detect": "Low",
|
||||
"unknown": "Low",
|
||||
"tcp-connection": "Very Low"
|
||||
}
|
121
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortRule.py
Executable file
121
nodes/http_transaction_handler/package/snort3_to_ips/SnortRule/SnortRule.py
Executable file
@ -0,0 +1,121 @@
|
||||
from snort3_to_ips.SnortRule.SnortRuleHeader import SnortRuleHeader
|
||||
from snort3_to_ips.SnortRule.SnortKW import SnortKW
|
||||
from snort3_to_ips.SnortRule.SnortKWParser import SnortKWParser
|
||||
from snort3_to_ips.Signature.IpsSignature import IpsSignature
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
class SnortRule:
|
||||
|
||||
def __init__(self, rule_header):
|
||||
self.header = SnortRuleHeader(rule_header)
|
||||
self.keywords = []
|
||||
self.sticky_buffer = "Default"
|
||||
self.dynamic_buffer = {}
|
||||
self.flow = "client_to_server"
|
||||
|
||||
def is_http_rule(self, parsed_body):
|
||||
return self.header.is_http_header() or "service:http" in parsed_body
|
||||
|
||||
def add_keyword(self, snort_rule):
|
||||
kw_parser = SnortKWParser()
|
||||
keyword, value, optional_modifiers = kw_parser.parse_kw_parameters(snort_rule)
|
||||
self.keywords.append(SnortKW(keyword, value, optional_modifiers))
|
||||
|
||||
def parse_body(self, input_snort_rule_body):
|
||||
for keyword in input_snort_rule_body:
|
||||
self.add_keyword(keyword)
|
||||
|
||||
def convert(self):
|
||||
signature = IpsSignature()
|
||||
for keyword in self.keywords:
|
||||
for converted_keyword in keyword.convert(self):
|
||||
signature.parse_data(converted_keyword.construct())
|
||||
return signature.output_signature()
|
||||
|
||||
def get_ips_context(self):
|
||||
return self.convert_http_map[self.sticky_buffer](self)
|
||||
|
||||
def convert_default(self):
|
||||
return {"part": "HTTP_RAW"}
|
||||
|
||||
def convert_pkt_data(self):
|
||||
raise SnortHookException("Unsupported keyword 'pkt_data'")
|
||||
|
||||
def convert_http_uri(self):
|
||||
return {"part": "HTTP_COMPLETE_URL_DECODED"}
|
||||
|
||||
def convert_http_raw_uri(self):
|
||||
return {"part": "HTTP_COMPLETE_URL_ENCODED"}
|
||||
|
||||
def convert_http_header(self):
|
||||
if self.flow == "client_to_server":
|
||||
if 'field' in self.dynamic_buffer.keys():
|
||||
return {"part": 'HTTP_REQUEST_HEADER_{}'.format(self.dynamic_buffer['field'].upper())}
|
||||
else:
|
||||
return {"part": "HTTP_REQUEST_HEADER"}
|
||||
elif self.flow == "server_to_client":
|
||||
if 'field' in self.dynamic_buffer.keys():
|
||||
return {"part": 'HTTP_RESPONSE_HEADER_{}'.format(self.dynamic_buffer['field'].upper())}
|
||||
else:
|
||||
return {"part": "HTTP_RESPONSE_HEADER"}
|
||||
|
||||
else:
|
||||
raise SnortHookException("Unknown Flow {}".format(self.flow))
|
||||
|
||||
def convert_http_raw_header(self):
|
||||
if self.flow == "client_to_server":
|
||||
return {"part": "HTTP_REQUEST_HEADER"}
|
||||
elif self.flow == "server_to_client":
|
||||
return {"part": "HTTP_RESPONSE_HEADER"}
|
||||
else:
|
||||
raise SnortHookException("Unknown Flow {}".format(self.flow))
|
||||
|
||||
def convert_http_method(self):
|
||||
return {"part": "HTTP_METHOD"}
|
||||
|
||||
def convert_http_client_body(self):
|
||||
return {"part": "HTTP_REQUEST_BODY"}
|
||||
|
||||
def convert_http_cookie(self):
|
||||
if self.flow == "client_to_server":
|
||||
return {"part": "HTTP_REQUEST_HEADER_COOKIE"}
|
||||
elif self.flow == "server_to_client":
|
||||
return {"part": "HTTP_RESPONSE_HEADER_COOKIE"}
|
||||
else:
|
||||
raise SnortHookException("Unknown Flow {}".format(self.flow))
|
||||
|
||||
def convert_http_raw_cookie(self):
|
||||
if self.flow == "client_to_server":
|
||||
return {"part": "HTTP_REQUEST_HEADER_COOKIE"}
|
||||
elif self.flow == "server_to_client":
|
||||
return {"part": "HTTP_RESPONSE_HEADER_COOKIE"}
|
||||
else:
|
||||
raise SnortHookException("Unknown Flow {}".format(self.flow))
|
||||
|
||||
def convert_http_stat_code(self):
|
||||
if self.flow == "client_to_server":
|
||||
raise SnortHookException("http_stat_code isn't supported with flow: to_server, from_client")
|
||||
elif self.flow == "server_to_client":
|
||||
return {"part": "HTTP_RESPONSE_CODE"}
|
||||
else:
|
||||
raise SnortHookException("Unknown Flow {}".format(self.flow))
|
||||
|
||||
def not_implemented(self):
|
||||
raise SnortHookException("unsupported keyword '{}'".format(self.sticky_buffer))
|
||||
|
||||
convert_http_map = {
|
||||
'Default': convert_default,
|
||||
'pkt_data': convert_pkt_data,
|
||||
'http_uri': convert_http_uri,
|
||||
'http_raw_uri': convert_http_raw_uri,
|
||||
'http_header': convert_http_header,
|
||||
'http_raw_header': convert_http_raw_header,
|
||||
'http_method': convert_http_method,
|
||||
'http_client_body': convert_http_client_body,
|
||||
'http_cookie': convert_http_cookie,
|
||||
'http_raw_cookie': convert_http_raw_cookie,
|
||||
'http_stat_code': convert_http_stat_code,
|
||||
'http_stat_msg': not_implemented,
|
||||
'http_encode': not_implemented
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
from exception import SnortHookException
|
||||
|
||||
class SnortRuleHeader:
|
||||
def __init__(self, rule_header_str):
|
||||
self.rules = {}
|
||||
rule_list = rule_header_str.split(" ")
|
||||
if len(rule_list) == 2:
|
||||
# alert http
|
||||
self.validate_and_parse_action(rule_list[0])
|
||||
self.validate_and_parse_protocol(rule_list[1])
|
||||
self.rules['source_ports'] = ""
|
||||
self.rules['destination_ports'] = ""
|
||||
self.rules['directional_op'] = ""
|
||||
elif len(rule_list) == 7:
|
||||
# alert http $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS
|
||||
self.validate_and_parse_action(rule_list[0])
|
||||
self.validate_and_parse_protocol(rule_list[1])
|
||||
self.validate_and_parse_directional_operator(rule_list[4])
|
||||
self.validate_and_parse_source_ports(rule_list[3])
|
||||
self.validate_and_parse_destination_ports(rule_list[6])
|
||||
else:
|
||||
raise SnortHookException("Invalid Snort rule header")
|
||||
|
||||
def validate_and_parse_action(self, action):
|
||||
if action in ['drop']:
|
||||
self.rules['action'] = action
|
||||
elif action in ['alert', 'log', 'pass', 'reject', 'sdrop']:
|
||||
pass
|
||||
# print("Header action {} not supported".format(action))
|
||||
else:
|
||||
raise SnortHookException("Unknown header action {}".format(action))
|
||||
|
||||
def validate_and_parse_protocol(self, protocol):
|
||||
if protocol in ['http']:
|
||||
self.rules['protocol'] = protocol
|
||||
elif protocol in ['tcp', 'udp', 'icmp', 'ip', 'file']:
|
||||
self.rules['protocol'] = protocol
|
||||
else:
|
||||
raise SnortHookException("Error: Unknown header protocol {}".format(protocol))
|
||||
|
||||
def validate_and_parse_directional_operator(self, directional_op):
|
||||
if directional_op in ['->', '<>']:
|
||||
self.rules['directional_op'] = directional_op
|
||||
else:
|
||||
raise SnortHookException("Error: Unknown unsupported header directional operator {}".format(directional_op))
|
||||
|
||||
def validate_and_parse_source_ports(self, ports):
|
||||
if ports in ['$HTTP_PORTS']:
|
||||
self.rules['source_ports'] = ports
|
||||
else:
|
||||
self.rules['source_ports'] = ""
|
||||
|
||||
def validate_and_parse_destination_ports(self, ports):
|
||||
if ports in ['$HTTP_PORTS']:
|
||||
self.rules['destination_ports'] = ports
|
||||
else:
|
||||
self.rules['destination_ports'] = ""
|
||||
|
||||
def is_http_header(self):
|
||||
return self.rules['protocol'] == 'http' or self.rules['destination_ports'] == "$HTTP_PORTS"
|
7
nodes/http_transaction_handler/package/snort3_to_ips/main.py
Executable file
7
nodes/http_transaction_handler/package/snort3_to_ips/main.py
Executable file
@ -0,0 +1,7 @@
|
||||
import snort3_to_ips.Signature.Signatures as Signatures
|
||||
|
||||
|
||||
def convert_incoming_rules(rules):
|
||||
signatures = Signatures.Signatures()
|
||||
signatures.load_snort_signatures(rules)
|
||||
return signatures.get_payload_data()
|
129
nodes/http_transaction_handler/package/snort3_to_ips/utils/utils.py
Executable file
129
nodes/http_transaction_handler/package/snort3_to_ips/utils/utils.py
Executable file
@ -0,0 +1,129 @@
|
||||
import hashlib
|
||||
import base64
|
||||
|
||||
from exception import SnortHookException
|
||||
|
||||
|
||||
def parse_snort_rules_line(line):
|
||||
header = line[0:line.find("(")].strip()
|
||||
tmp_body = line[line.find("(") + 1:line.rfind(")")].replace("\n", "").strip().split(";")
|
||||
body = []
|
||||
tmp_body_segment = ""
|
||||
for rule in tmp_body:
|
||||
if len(rule) == 0:
|
||||
continue
|
||||
rule = rule.strip()
|
||||
if rule[len(rule) - 1] == "\\":
|
||||
tmp_body_segment += "{};".format(rule[:len(rule) - 1])
|
||||
else:
|
||||
body.append(tmp_body_segment + rule)
|
||||
tmp_body_segment = ""
|
||||
|
||||
return header, body
|
||||
|
||||
|
||||
def is_hex_segment_in_str(value):
|
||||
if value.count("|") - value.count("\\|") > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_invalid_line(line):
|
||||
tmp_line = line.strip()
|
||||
return len(tmp_line) == 0 or tmp_line[0] == "#"
|
||||
|
||||
|
||||
def generate_version_id(data, hash_mode="md5", input_mode="decoded_data"):
|
||||
if hash_mode == "md5":
|
||||
hash_mod = hashlib.md5()
|
||||
elif hash_mode == "sha1":
|
||||
hash_mod = hashlib.sha1()
|
||||
else:
|
||||
return ""
|
||||
if input_mode == "file":
|
||||
with open(data, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
hash_mod.update(chunk)
|
||||
elif input_mode == "decoded_data":
|
||||
hash_mod.update(data.encode())
|
||||
return hash_mod.hexdigest()
|
||||
|
||||
|
||||
def verify_custom_signatures(signatures):
|
||||
if signatures is None:
|
||||
return False
|
||||
return signatures['isFileExist'] and signatures['size'] != 0
|
||||
|
||||
|
||||
def decode_custom_signature(signatures):
|
||||
data = signatures.split(",", 1)
|
||||
metadata = data[0]
|
||||
if metadata == 'data:':
|
||||
return ""
|
||||
elif metadata != 'data:application/octet-stream;base64':
|
||||
raise SnortHookException("Invalid Snort file")
|
||||
base64_message = base64.b64decode(data[1])
|
||||
return base64_message.decode("utf-8")
|
||||
|
||||
|
||||
def prepare_warnings_log(warnings):
|
||||
if not warnings:
|
||||
return []
|
||||
if len(warnings) <= 10:
|
||||
ret_warnings = []
|
||||
for warning in warnings:
|
||||
if warning['errorType'] == "SnortRule":
|
||||
tmp_id = warning['id']
|
||||
ret_warnings.append({"id": warning['id'],
|
||||
"name": "Snort Warning",
|
||||
"type": "Web Application",
|
||||
"sub_type": "Snort Conversion",
|
||||
"message": "Asset {}, skipped line {}: {}".format(warning["assetName"], warning['Line'], warning['Error'])
|
||||
})
|
||||
else:
|
||||
assets_errors = {}
|
||||
for warning in warnings:
|
||||
if warning['errorType'] == "SnortRule":
|
||||
tmp_id = warning['id']
|
||||
asset_name = warning["assetName"]
|
||||
if asset_name not in assets_errors.keys():
|
||||
assets_errors[asset_name] = {}
|
||||
if warning['Error'] not in assets_errors[asset_name].keys():
|
||||
assets_errors[asset_name][warning['Error']] = 1
|
||||
else:
|
||||
assets_errors[asset_name][warning['Error']] += 1
|
||||
|
||||
ret_warnings = []
|
||||
for asset_name in assets_errors.keys():
|
||||
for err in assets_errors[asset_name].keys():
|
||||
if assets_errors[asset_name][err] == 1:
|
||||
message_format = "Asset {}: skipped {} {} time"
|
||||
else:
|
||||
message_format = "Asset {}: skipped {} {} times"
|
||||
ret_warnings.append({"id": tmp_id,
|
||||
"name": "Snort Warning",
|
||||
"type": "Web Application",
|
||||
"sub_type": "Snort Conversion",
|
||||
"message": message_format.format(asset_name, err, assets_errors[asset_name][err])
|
||||
})
|
||||
for warning in warnings:
|
||||
if warning['errorType'] != "SnortRule":
|
||||
tmp_id = warning['id']
|
||||
ret_warnings.append({"id": warning['id'],
|
||||
"name": "Snort Warning",
|
||||
"type": "Web Application",
|
||||
"sub_type": "Snort Conversion",
|
||||
"message": warning['Error']
|
||||
})
|
||||
if len(ret_warnings) == 1:
|
||||
final_message_format = "To remove warning, please edit the Snort signatures file"
|
||||
else:
|
||||
final_message_format = "To remove warnings, please edit the Snort signatures file"
|
||||
ret_warnings.append({"id": tmp_id,
|
||||
"name": "Snort Warning",
|
||||
"type": "Web Application",
|
||||
"sub_type": "Snort Conversion",
|
||||
"message": final_message_format
|
||||
})
|
||||
return ret_warnings
|
||||
|
30
nodes/http_transaction_handler/package/snort_to_ips_local.py
Executable file
30
nodes/http_transaction_handler/package/snort_to_ips_local.py
Executable file
@ -0,0 +1,30 @@
|
||||
import os
|
||||
import snort3_to_ips.Signature.Signatures as Signatures
|
||||
import sys
|
||||
|
||||
|
||||
def convert_snort_to_ips_package(input_pf, output_pf, error_pf):
|
||||
signatures = Signatures.Signatures()
|
||||
with open(input_pf) as f:
|
||||
input_data = f.read()
|
||||
signatures.load_snort_signatures(input_data)
|
||||
signatures.output_ips_signature_package(output_pf)
|
||||
signatures.output_errors(error_pf)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: python3 snort_to_ips_local.py <input_file> <output_file> <error_file>")
|
||||
exit(1)
|
||||
|
||||
# Path to snort 3 rules file
|
||||
in_pf = os.path.join("snort3_to_ips", "data", sys.argv[1])
|
||||
|
||||
# Path to output file (will create one if it does not exist)
|
||||
out_pf = os.path.join("snort3_to_ips", "data", sys.argv[2])
|
||||
|
||||
# Path to output errors file (will create one if it does not exist)
|
||||
err_pf = os.path.join("snort3_to_ips", "data", sys.argv[3])
|
||||
|
||||
convert_snort_to_ips_package(in_pf, out_pf, err_pf)
|
||||
|
Loading…
x
Reference in New Issue
Block a user