From 582791e37ae2e254fd5bfc947e0fff234dbe8ded Mon Sep 17 00:00:00 2001 From: Ned Wright Date: Sun, 24 Sep 2023 10:28:57 +0000 Subject: [PATCH] Sep_24_2023-Dev --- README.md | 3 +- .../evaluators/http_transaction_data_eval.cc | 48 + .../generic_rulebase/generic_rulebase.cc | 1 + .../evaluators/http_transaction_data_eval.h | 13 + components/include/i_local_policy_mgmt_gen.h | 10 +- components/include/i_orchestration_status.h | 1 + components/include/i_orchestration_tools.h | 4 +- components/include/orchestration_comp.h | 4 +- components/include/orchestration_status.h | 2 + components/include/orchestration_tools.h | 12 +- .../rest_api/orchestration_check_update.h | 54 +- components/include/rate_limit.h | 32 + components/include/rate_limit_config.h | 142 ++ components/security_apps/CMakeLists.txt | 2 + .../layer_7_access_control.cc | 4 +- .../layer_7_access_control_ut.cc | 2 +- .../local_policy_mgmt_gen/CMakeLists.txt | 23 + .../access_control_practice.cc | 245 +++ .../appsec_practice_section.cc | 752 ++++++++ .../local_policy_mgmt_gen/configmaps.cc | 58 + .../exceptions_section.cc | 418 +++++ .../include/access_control_practice.h | 192 ++ .../include/appsec_practice_section.h | 486 +++++ .../include/configmaps.h | 41 + .../include/exceptions_section.h | 171 ++ .../include/ingress_data.h | 125 ++ .../include/k8s_policy_utils.h | 118 ++ .../include/local_policy_common.h | 144 ++ .../include/new_appsec_linux_policy.h | 84 + .../include/new_appsec_policy_crd_parser.h | 82 + .../include/new_custom_response.h | 51 + .../include/new_exceptions.h | 67 + .../include/new_log_trigger.h | 172 ++ .../include/new_practice.h | 589 ++++++ .../include/new_trusted_sources.h | 74 + .../include/policy_maker_utils.h | 266 +++ .../include/rules_config_section.h | 190 ++ .../include/settings_section.h | 68 + .../include/snort_section.h | 50 + .../include/triggers_section.h | 305 ++++ .../include/trusted_sources_section.h | 108 ++ .../local_policy_mgmt_gen/ingress_data.cc | 149 ++ .../local_policy_mgmt_gen/k8s_policy_utils.cc | 587 ++++++ .../local_policy_mgmt_gen.cc | 128 ++ .../new_appsec_linux_policy.cc | 72 + .../new_appsec_policy_crd_parser.cc | 154 ++ .../new_custom_response.cc | 99 + .../local_policy_mgmt_gen/new_exceptions.cc | 187 ++ .../local_policy_mgmt_gen/new_log_trigger.cc | 321 ++++ .../local_policy_mgmt_gen/new_practice.cc | 986 ++++++++++ .../new_trusted_sources.cc | 118 ++ .../policy_maker_utils.cc | 1590 +++++++++++++++++ .../rules_config_section.cc | 369 ++++ .../local_policy_mgmt_gen/settings_section.cc | 87 + .../local_policy_mgmt_gen/snort_section.cc | 54 + .../local_policy_mgmt_gen/triggers_section.cc | 535 ++++++ .../trusted_sources_section.cc | 152 ++ .../orchestration/CMakeLists.txt | 1 - .../checkpoint_product_handlers.h | 84 +- .../details_resolver_impl.h | 19 +- .../details_resolving_handler.cc | 4 +- .../details_resolving_handler.h | 2 + .../orchestration/downloader/curl_client.cc | 36 +- .../orchestration/downloader/curl_client.h | 1 + .../downloader/downloader_ut/downloader_ut.cc | 25 +- .../orchestration/downloader/http_client.h | 2 +- .../orchestration/downloader/https_client.cc | 9 +- .../health_check/health_check.cc | 71 +- .../health_check_ut/health_check_ut.cc | 2 +- .../include/declarative_policy_utils.h | 13 +- .../orchestration/include/fog_authenticator.h | 1 + .../orchestration/include/get_status_rest.h | 2 + .../include/mock/mock_orchestration_status.h | 1 + .../orchestration/include/namespace_data.h | 35 + .../manifest_controller.cc | 34 +- .../modules_ut/orchestration_status_ut.cc | 20 +- .../modules/orchestration_status.cc | 23 +- .../orchestration/orchestration_comp.cc | 8 +- .../orchestration_tools/CMakeLists.txt | 2 +- .../orchestration_tools/namespace_data.cc | 117 ++ .../orchestration_tools.cc | 114 +- .../orchestration_tools_ut.cc | 87 +- .../orchestration_multitenant_ut.cc | 8 +- .../orchestration_ut/orchestration_ut.cc | 30 +- .../service_controller_ut.cc | 42 +- .../update_communication/CMakeLists.txt | 2 +- .../declarative_policy_utils.cc | 17 +- .../update_communication/fog_authenticator.cc | 5 + .../fog_helper_open_source.cc | 9 + .../security_apps/rate_limit/CMakeLists.txt | 6 + .../security_apps/rate_limit/rate_limit.cc | 535 ++++++ .../rate_limit/rate_limit_config.cc | 157 ++ .../security_apps/waap/include/i_waapConfig.h | 1 + .../waap/waap_clib/WaapConfigBase.cc | 6 + .../waap/waap_clib/WaapConfigBase.h | 1 + .../agent_core_utilities.cc | 35 + .../agent_core_utilities_ut.cc | 14 +- core/environment/environment.cc | 1 - .../resources/report/report_enums.h | 3 +- .../utilities/agent_core_utilities.h | 8 + core/logging/log_generator.cc | 5 +- core/report/tag_and_enum_management.cc | 1 + nodes/http_transaction_handler/CMakeLists.txt | 9 + nodes/http_transaction_handler/main.cc | 2 + .../orchestration/package/open-appsec-ctl.sh | 18 +- .../package/orchestration_package.sh | 27 +- 106 files changed, 12287 insertions(+), 169 deletions(-) create mode 100755 components/include/rate_limit.h create mode 100755 components/include/rate_limit_config.h create mode 100644 components/security_apps/local_policy_mgmt_gen/CMakeLists.txt create mode 100755 components/security_apps/local_policy_mgmt_gen/access_control_practice.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/appsec_practice_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/configmaps.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/exceptions_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/include/access_control_practice.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/appsec_practice_section.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/configmaps.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/exceptions_section.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/ingress_data.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/k8s_policy_utils.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/local_policy_common.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_appsec_linux_policy.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_custom_response.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_exceptions.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_log_trigger.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_practice.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/new_trusted_sources.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/rules_config_section.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/settings_section.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/snort_section.h create mode 100644 components/security_apps/local_policy_mgmt_gen/include/triggers_section.h create mode 100755 components/security_apps/local_policy_mgmt_gen/include/trusted_sources_section.h create mode 100755 components/security_apps/local_policy_mgmt_gen/ingress_data.cc create mode 100644 components/security_apps/local_policy_mgmt_gen/k8s_policy_utils.cc create mode 100644 components/security_apps/local_policy_mgmt_gen/local_policy_mgmt_gen.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_appsec_linux_policy.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_custom_response.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_exceptions.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_log_trigger.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_practice.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/new_trusted_sources.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/policy_maker_utils.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/rules_config_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/settings_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/snort_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/triggers_section.cc create mode 100755 components/security_apps/local_policy_mgmt_gen/trusted_sources_section.cc create mode 100644 components/security_apps/orchestration/include/namespace_data.h create mode 100644 components/security_apps/orchestration/orchestration_tools/namespace_data.cc create mode 100755 components/security_apps/orchestration/update_communication/fog_helper_open_source.cc create mode 100644 components/security_apps/rate_limit/CMakeLists.txt create mode 100755 components/security_apps/rate_limit/rate_limit.cc create mode 100755 components/security_apps/rate_limit/rate_limit_config.cc diff --git a/README.md b/README.md index 0c61321..217d408 100644 --- a/README.md +++ b/README.md @@ -104,12 +104,13 @@ Before compiling the services, you'll need to ensure the latest development vers * GTest * GMock * cURL +* Hiredis An example of installing the packages on Alpine: ```bash $ apk update - $ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev + $ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev hiredis-dev ``` ## Compiling and packaging the agent code diff --git a/components/generic_rulebase/evaluators/http_transaction_data_eval.cc b/components/generic_rulebase/evaluators/http_transaction_data_eval.cc index fa90b6a..d6560fb 100755 --- a/components/generic_rulebase/evaluators/http_transaction_data_eval.cc +++ b/components/generic_rulebase/evaluators/http_transaction_data_eval.cc @@ -20,6 +20,9 @@ #include "environment/evaluator_templates.h" #include "i_environment.h" #include "singleton.h" +#include "debug.h" + +USE_DEBUG_FLAG(D_RULEBASE_CONFIG); using namespace std; using namespace EnvironmentHelper; @@ -55,6 +58,51 @@ EqualHost::evalVariable() const return lower_host_ctx == lower_host; } +WildcardHost::WildcardHost(const vector ¶ms) +{ + if (params.size() != 1) reportWrongNumberOfParams("WildcardHost", params.size(), 1, 1); + host = params[0]; +} + +Maybe +WildcardHost::evalVariable() const +{ + I_Environment *env = Singleton::Consume::by(); + auto host_ctx = env->get(HttpTransactionData::host_name_ctx); + + if (!host_ctx.ok()) + { + return false; + } + + string lower_host_ctx = host_ctx.unpack(); + transform(lower_host_ctx.begin(), lower_host_ctx.end(), lower_host_ctx.begin(), ::tolower); + + dbgTrace(D_RULEBASE_CONFIG) << "found host in current context: " << lower_host_ctx; + + size_t pos = lower_host_ctx.find_first_of("."); + if (pos == string::npos) { + return false; + } + + lower_host_ctx = "*" + lower_host_ctx.substr(pos, lower_host_ctx.length()); + + string lower_host = host; + transform(lower_host.begin(), lower_host.end(), lower_host.begin(), ::tolower); + + dbgTrace(D_RULEBASE_CONFIG) + << "trying to match host context with its corresponding wildcard address: " + << lower_host_ctx + << ". Matcher host: " + << lower_host; + + if (lower_host_ctx == lower_host) return true; + pos = lower_host_ctx.find_last_of(':'); + if (pos == string::npos) return false; + lower_host_ctx = string(lower_host_ctx.data(), pos); + return lower_host_ctx == lower_host; +} + EqualListeningIP::EqualListeningIP(const vector ¶ms) { if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1); diff --git a/components/generic_rulebase/generic_rulebase.cc b/components/generic_rulebase/generic_rulebase.cc index 4f115c3..d4fd8f9 100755 --- a/components/generic_rulebase/generic_rulebase.cc +++ b/components/generic_rulebase/generic_rulebase.cc @@ -75,6 +75,7 @@ GenericRulebase::Impl::preload() addMatcher(); addMatcher(); addMatcher(); + addMatcher(); addMatcher(); addMatcher(); addMatcher(); diff --git a/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h b/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h index 8603bc5..e9fb041 100755 --- a/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h +++ b/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h @@ -32,6 +32,19 @@ private: std::string host; }; +class WildcardHost : public EnvironmentEvaluator, Singleton::Consume +{ +public: + WildcardHost(const std::vector ¶ms); + + static std::string getName() { return "WildcardHost"; } + + Maybe evalVariable() const override; + +private: + std::string host; +}; + class EqualListeningIP : public EnvironmentEvaluator, Singleton::Consume { public: diff --git a/components/include/i_local_policy_mgmt_gen.h b/components/include/i_local_policy_mgmt_gen.h index a4ae7ed..d1874ad 100755 --- a/components/include/i_local_policy_mgmt_gen.h +++ b/components/include/i_local_policy_mgmt_gen.h @@ -14,13 +14,15 @@ #ifndef __I_LOCAL_POLICY_MGMT_GEN_H__ #define __I_LOCAL_POLICY_MGMT_GEN_H__ +#include "i_env_details.h" + class I_LocalPolicyMgmtGen { public: - virtual std::string parsePolicy(const std::string &policy_version) = 0; - virtual const std::string & getAgentPolicyPath(void) const = 0; - virtual const std::string & getLocalPolicyPath(void) const = 0; - virtual void setPolicyPath(const std::string &new_local_policy_path) = 0; + virtual std::string generateAppSecLocalPolicy( + EnvType env_type, + const std::string &policy_version, + const std::string &local_policy_path) = 0; protected: ~I_LocalPolicyMgmtGen() {} diff --git a/components/include/i_orchestration_status.h b/components/include/i_orchestration_status.h index 4305c55..d99bb0c 100755 --- a/components/include/i_orchestration_status.h +++ b/components/include/i_orchestration_status.h @@ -34,6 +34,7 @@ public: virtual const std::string & getUpdateTime() const = 0; virtual const std::string & getLastManifestUpdate() const = 0; virtual const std::string & getPolicyVersion() const = 0; + virtual const std::string & getWaapModelVersion() const = 0; virtual const std::string & getLastPolicyUpdate() const = 0; virtual const std::string & getLastSettingsUpdate() const = 0; virtual const std::string & getUpgradeMode() const = 0; diff --git a/components/include/i_orchestration_tools.h b/components/include/i_orchestration_tools.h index 18da6c9..692d513 100755 --- a/components/include/i_orchestration_tools.h +++ b/components/include/i_orchestration_tools.h @@ -106,8 +106,9 @@ public: const std::string &profile_id = "") const = 0; virtual bool isNonEmptyFile(const std::string &path) const = 0; + virtual std::shared_ptr fileStreamWrapper(const std::string &path) const = 0; virtual Maybe readFile(const std::string &path) const = 0; - virtual bool writeFile(const std::string &text, const std::string &path) const = 0; + virtual bool writeFile(const std::string &text, const std::string &path, bool append_mode = false) const = 0; virtual bool removeFile(const std::string &path) const = 0; virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0; virtual void deleteVirtualTenantProfileFiles( @@ -116,6 +117,7 @@ public: const std::string &conf_path) const = 0; virtual bool copyFile(const std::string &src_path, const std::string &dst_path) const = 0; virtual bool doesFileExist(const std::string &file_path) const = 0; + virtual void getClusterId() const = 0; virtual void fillKeyInJson( const std::string &filename, const std::string &_key, diff --git a/components/include/orchestration_comp.h b/components/include/orchestration_comp.h index 2ab061d..5a02dcd 100755 --- a/components/include/orchestration_comp.h +++ b/components/include/orchestration_comp.h @@ -31,6 +31,7 @@ #include "i_environment.h" #include "i_tenant_manager.h" #include "i_package_handler.h" +#include "i_env_details.h" #include "component.h" class OrchestrationComp @@ -52,7 +53,8 @@ class OrchestrationComp Singleton::Consume, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume { public: OrchestrationComp(); diff --git a/components/include/orchestration_status.h b/components/include/orchestration_status.h index 84879a4..b9adb63 100755 --- a/components/include/orchestration_status.h +++ b/components/include/orchestration_status.h @@ -24,6 +24,7 @@ #include "i_time_get.h" #include "i_mainloop.h" #include "i_agent_details.h" +#include "i_details_resolver.h" #include "customized_cereal_map.h" class OrchestrationStatus @@ -32,6 +33,7 @@ class OrchestrationStatus Singleton::Provide, Singleton::Consume, Singleton::Consume, + Singleton::Consume, Singleton::Consume, Singleton::Consume { diff --git a/components/include/orchestration_tools.h b/components/include/orchestration_tools.h index caa851c..c85eed3 100755 --- a/components/include/orchestration_tools.h +++ b/components/include/orchestration_tools.h @@ -20,13 +20,23 @@ #include "i_shell_cmd.h" #include "i_tenant_manager.h" #include "component.h" +#include "i_env_details.h" +#include "i_messaging.h" +#include "i_environment.h" +#include "i_agent_details.h" +#include "i_mainloop.h" class OrchestrationTools : public Component, Singleton::Provide, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume { public: OrchestrationTools(); diff --git a/components/include/orchestrator/rest_api/orchestration_check_update.h b/components/include/orchestrator/rest_api/orchestration_check_update.h index 2304ecd..26bf7d5 100644 --- a/components/include/orchestrator/rest_api/orchestration_check_update.h +++ b/components/include/orchestrator/rest_api/orchestration_check_update.h @@ -111,6 +111,26 @@ public: public: UpgradeSchedule() = default; + UpgradeSchedule(const UpgradeSchedule &other) + { + mode = other.mode; + time = other.time; + duration_hours = other.duration_hours; + days = other.days; + } + + UpgradeSchedule & + operator=(const UpgradeSchedule &other) + { + if (this != &other) { + mode = other.mode; + time = other.time; + duration_hours = other.duration_hours; + days = other.days; + } + return *this; + } + void init(const std::string &_upgrade_mode) { mode = _upgrade_mode; } void @@ -142,6 +162,22 @@ public: C2S_LABEL_OPTIONAL_PARAM(std::vector, days, "upgradeDay"); }; + class LocalConfigurationSettings : public ClientRest + { + public: + LocalConfigurationSettings() = default; + + void + setUpgradeSchedule(const UpgradeSchedule &schedule) + { + upgrade_schedule.setActive(true); + upgrade_schedule.get() = schedule; + } + + private: + C2S_LABEL_OPTIONAL_PARAM(UpgradeSchedule, upgrade_schedule, "upgradeSchedule"); + }; + CheckUpdateRequest( const std::string &_manifest, const std::string &_policy, @@ -224,8 +260,10 @@ public: void setUpgradeFields(const std::string &_upgrade_mode) { - upgrade_schedule.setActive(true); - upgrade_schedule.get().init(_upgrade_mode); + UpgradeSchedule upgrade_schedule; + upgrade_schedule.init(_upgrade_mode); + local_configuration_settings.setActive(true); + local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule); } void @@ -235,12 +273,14 @@ public: const uint &_upgrade_duration_hours, const std::vector &_upgrade_days) { - upgrade_schedule.setActive(true); + UpgradeSchedule upgrade_schedule; if (!_upgrade_days.empty()) { - upgrade_schedule.get().init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days); - return; + upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days); + } else { + upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours); } - upgrade_schedule.get().init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours); + local_configuration_settings.setActive(true); + local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule); } private: @@ -297,7 +337,7 @@ private: C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type"); C2S_LABEL_PARAM(std::string, policy_version, "policyVersion"); - C2S_LABEL_OPTIONAL_PARAM(UpgradeSchedule, upgrade_schedule, "upgradeSchedule"); + C2S_LABEL_OPTIONAL_PARAM(LocalConfigurationSettings, local_configuration_settings, "localConfigurationSettings"); S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_policy, "virtualPolicy"); S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings"); diff --git a/components/include/rate_limit.h b/components/include/rate_limit.h new file mode 100755 index 0000000..3c3e726 --- /dev/null +++ b/components/include/rate_limit.h @@ -0,0 +1,32 @@ +#ifndef __RATE_LIMIT_H_ +#define __RATE_LIMIT_H_ + +#include + +#include "component.h" +#include "singleton.h" +#include "i_mainloop.h" +#include "i_environment.h" + +class RateLimit + : + public Component, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume +{ +public: + RateLimit(); + ~RateLimit(); + + void preload() override; + + void init() override; + void fini() override; + +private: + class Impl; + std::unique_ptr pimpl; +}; + +#endif // __RATE_LIMIT_H_ diff --git a/components/include/rate_limit_config.h b/components/include/rate_limit_config.h new file mode 100755 index 0000000..b464d3e --- /dev/null +++ b/components/include/rate_limit_config.h @@ -0,0 +1,142 @@ +#ifndef __RATE_LIMIT_CONFIG_H__ +#define __RATE_LIMIT_CONFIG_H__ + +#include +#include +#include +#include + +#include "debug.h" +#include "generic_rulebase/rulebase_config.h" +#include "generic_rulebase/triggers_config.h" +#include "generic_rulebase/evaluators/trigger_eval.h" + +USE_DEBUG_FLAG(D_REVERSE_PROXY); + +class RateLimitTrigger +{ +public: + void + load(cereal::JSONInputArchive &ar); + + const std::string & getTriggerId() const { return id; } + +private: + std::string id; +}; + +class RateLimitRule +{ +public: + void load(cereal::JSONInputArchive &ar); + void prepare(const std::string &asset_id, int zone_id); + + operator bool() const + { + if (uri.empty()) { + dbgTrace(D_REVERSE_PROXY) << "Recived empty URI in rate-limit rule"; + return false; + } + + if (uri.at(0) != '/') { + dbgWarning(D_REVERSE_PROXY) + << "Recived invalid rate-limit URI in rate-limit rule: " + << uri + << " rate-limit URI must start with /"; + return false; + } + + if (limit <= 0) { + dbgWarning(D_REVERSE_PROXY) + << "Recived invalid rate-limit limit in rate-limit rule: " + << limit + << " rate-limit rule limit must be positive"; + return false; + } + + return true; + } + + friend std::ostream & + operator<<(std::ostream &os, const RateLimitRule &rule) + { + os << "Uri: " << rule.uri << ", Rate scope: " << rule.scope << ", Limit: " << rule.limit; + + return os; + } + + int getRateLimit() const { return limit; } + const std::string & getRateLimitZone() const { return limit_req_zone_template_value; } + const std::string & getRateLimitReq() const { return limit_req_template_value; } + const std::string & getRateLimitUri() const { return uri; } + const std::string & getRateLimitScope() const { return scope; } + const LogTriggerConf & getRateLimitTrigger() const { return trigger; } + const std::vector & getRateLimitTriggers() const { return rate_limit_triggers; } + + bool isRootLocation() const; + + bool operator==(const RateLimitRule &rhs) { return uri == rhs.uri; } + bool operator<(const RateLimitRule &rhs) { return uri < rhs.uri; } + bool isExactMatch() const { return exact_match || (!uri.empty() && uri.back() != '/'); } + void setExactMatch() { exact_match = true; } + void appendSlash() { uri += '/'; } + +private: + std::string uri; + std::string scope; + std::string limit_req_template_value; + std::string limit_req_zone_template_value; + std::string cache_size = "5m"; + std::vector rate_limit_triggers; + LogTriggerConf trigger; + int limit; + bool exact_match = false; +}; + +class RateLimitConfig +{ +public: + void load(cereal::JSONInputArchive &ar); + void addSiblingRateLimitRule(RateLimitRule &rule); + void prepare(); + + const std::vector & getRateLimitRules() const { return rate_limit_rules; } + const std::string & getRateLimitMode() const { return mode; } + + const LogTriggerConf + getRateLimitTrigger(const std::string &nginx_uri) const + { + const RateLimitRule rule = findLongestMatchingRule(nginx_uri); + + std::set rate_limit_triggers_set; + for (const RateLimitTrigger &rate_limit_trigger : rule.getRateLimitTriggers()) { + dbgTrace(D_REVERSE_PROXY) + << "Adding trigger ID: " + << rate_limit_trigger.getTriggerId() + << " of rule URI: " + << rule.getRateLimitUri() + << " to the context set"; + rate_limit_triggers_set.insert(rate_limit_trigger.getTriggerId()); + } + + ScopedContext ctx; + ctx.registerValue>(TriggerMatcher::ctx_key, rate_limit_triggers_set); + return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log"); + } + + static void setIsActive(bool _is_active) { is_active |= _is_active; } + + static void resetIsActive() { is_active = false; } + + static bool isActive() { return is_active; } + +private: + const RateLimitRule + findLongestMatchingRule(const std::string &nginx_uri) const; + + static bool is_active; + std::string mode; + std::vector rate_limit_rules; +}; + +#endif // __RATE_LIMIT_CONFIG_H__ diff --git a/components/security_apps/CMakeLists.txt b/components/security_apps/CMakeLists.txt index ca6c3ad..bfde75c 100644 --- a/components/security_apps/CMakeLists.txt +++ b/components/security_apps/CMakeLists.txt @@ -1,4 +1,6 @@ add_subdirectory(ips) add_subdirectory(layer_7_access_control) +add_subdirectory(local_policy_mgmt_gen) add_subdirectory(orchestration) +add_subdirectory(rate_limit) add_subdirectory(waap) diff --git a/components/security_apps/layer_7_access_control/layer_7_access_control.cc b/components/security_apps/layer_7_access_control/layer_7_access_control.cc index e254a5e..299e8da 100644 --- a/components/security_apps/layer_7_access_control/layer_7_access_control.cc +++ b/components/security_apps/layer_7_access_control/layer_7_access_control.cc @@ -74,7 +74,7 @@ public: getCrowdsecEventId() const { if (!crowdsec_event_id) return genError("Empty ID"); - return LogField("externalVendorRecommendationId", crowdsec_event_id); + return LogField("externalVendorRecommendationId", to_string(crowdsec_event_id)); } bool isMalicious() const { return type == "ban"; } @@ -280,6 +280,8 @@ Layer7AccessControl::Impl::generateLog(const string &source_ip, const Intelligen << LogField("sourceIP", source_ip) << LogField("externalVendorName", "CrowdSec") << LogField("waapIncidentType", "CrowdSec") + << LogField("practiceSubType", "Web Access Control") + << LogField("practiceType", "Access Control") << ip_reputation.getCrowdsecEventId() << ip_reputation.getType() << ip_reputation.getOrigin() diff --git a/components/security_apps/layer_7_access_control/layer_7_access_control_ut/layer_7_access_control_ut.cc b/components/security_apps/layer_7_access_control/layer_7_access_control_ut/layer_7_access_control_ut.cc index 361438a..d722443 100644 --- a/components/security_apps/layer_7_access_control/layer_7_access_control_ut/layer_7_access_control_ut.cc +++ b/components/security_apps/layer_7_access_control/layer_7_access_control_ut/layer_7_access_control_ut.cc @@ -248,7 +248,7 @@ Layer7AccessControlTest::verifyReport( EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\"")); EXPECT_THAT(log, HasSubstr("\"waapIncidentType\": \"CrowdSec\"")); - EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": 2253734")); + EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": \"2253734\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAction\": \"ban\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\"")); diff --git a/components/security_apps/local_policy_mgmt_gen/CMakeLists.txt b/components/security_apps/local_policy_mgmt_gen/CMakeLists.txt new file mode 100644 index 0000000..d76674b --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/CMakeLists.txt @@ -0,0 +1,23 @@ +include_directories(include) +add_library(local_policy_mgmt_gen + appsec_practice_section.cc + exceptions_section.cc + ingress_data.cc + rules_config_section.cc + settings_section.cc + snort_section.cc + triggers_section.cc + trusted_sources_section.cc + policy_maker_utils.cc + k8s_policy_utils.cc + local_policy_mgmt_gen.cc + new_appsec_policy_crd_parser.cc + new_appsec_linux_policy.cc + new_custom_response.cc + new_trusted_sources.cc + new_log_trigger.cc + new_practice.cc + new_exceptions.cc + access_control_practice.cc + configmaps.cc +) diff --git a/components/security_apps/local_policy_mgmt_gen/access_control_practice.cc b/components/security_apps/local_policy_mgmt_gen/access_control_practice.cc new file mode 100755 index 0000000..329a4b6 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/access_control_practice.cc @@ -0,0 +1,245 @@ +// 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 "access_control_practice.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"prevent", "detect", "inactive"}; +static const set valid_units = {"minute", "second"}; + +static const std::unordered_map key_to_mode_val = { + { "prevent-learn", "Prevent"}, + { "detect-learn", "Detect"}, + { "prevent", "Prevent"}, + { "detect", "Detect"}, + { "inactive", "Inactive"} +}; + +static const std::unordered_map key_to_units_val = { + { "second", "Second"}, + { "minute", "Minute"} +}; + +void +RateLimitRulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("type", type) + ); +} + +const string & +RateLimitRulesTriggerSection::getName() const +{ + return name; +} + +void +RateLimitRulesSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("URI", uri), + cereal::make_nvp("scope", key_to_units_val.at(scope)), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("limit", limit) + ); +} + +RateLimitSection::RateLimitSection( + const string &asset_name, + const string &url, + const string &uri, + const std::string &_mode, + const std::string &_practice_id, + const std::string &_name, + const std::vector &_rules) + : + mode(_mode), + practice_id(_practice_id), + name(_name), + rules(_rules) +{ + bool any = asset_name == "Any" && url == "Any" && uri == "Any"; + string asset_id = any ? "Any" : url+uri; + context = "assetId(" + asset_id + ")"; +} + +void +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("practiceId", practice_id), + cereal::make_nvp("name", name), + cereal::make_nvp("rules", rules) + ); +} + +const string & +RateLimitSection::getId() const +{ + return practice_id; +} + +const string & +RateLimitSection::getName() const +{ + return name; +} + +const string & +RateLimitSection::getMode() const +{ + return mode; +} + +void +AccessControlRulebaseSection::save(cereal::JSONOutputArchive &out_ar) const +{ + vector empty; + out_ar( + cereal::make_nvp("accessControl", empty), + cereal::make_nvp("traditionalFirewall", empty), + cereal::make_nvp("l4firewall", empty), + cereal::make_nvp("rateLimit", rate_limit) + ); +} + +void +AccessControlRulebaseWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", rule_base) + ); +} + +void +AccessControlRateLimiteRules::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limite rules"; + parseAppsecJSONKey("limit", limit, archive_in); + parseAppsecJSONKey("uri", uri, archive_in); + parseAppsecJSONKey("unit", unit, archive_in); + if (valid_units.count(unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "Access control rate limite rules units invalid: " + << unit; + } + parseAppsecJSONKey("comment", comment, archive_in); + parseAppsecJSONKey>("triggers", triggers, archive_in); +} + +const vector +AccessControlRateLimiteRules::getTriggers() const +{ + return triggers; +} + +RateLimitRulesSection +AccessControlRateLimiteRules::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const +{ + string id = ""; + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to create random id"; + } + vector triggers_section; + string trigger_name = trigger.getName().substr(trigger.getName().find("/") + 1); + if (find(triggers.begin(), triggers.end(), trigger_name) != triggers.end()) { + triggers_section.push_back(trigger); + } + return RateLimitRulesSection( + limit, + id, + uri, + unit, + triggers_section + ); +} + +void +AccessControlRateLimit::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limit"; + parseAppsecJSONKey("overrideMode", mode, archive_in, "Inactive"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << mode; + } + parseAppsecJSONKey>("rules", rules, archive_in); +} + +vector +AccessControlRateLimit::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const +{ + vector rules_section; + for (const AccessControlRateLimiteRules &rule : rules) { + rules_section.push_back(rule.createRateLimitRulesSection(trigger)); + } + return rules_section; +} + +const vector & +AccessControlRateLimit::getRules() const +{ + return rules; +} + +const string & +AccessControlRateLimit::getMode() const +{ + return mode; +} + +void +AccessControlPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + + parseAppsecJSONKey("name", practice_name, archive_in); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("rateLimit", rate_limit, archive_in); +} + +void +AccessControlPracticeSpec::setName(const string &_name) +{ + practice_name = _name; +} + +const AccessControlRateLimit & +AccessControlPracticeSpec::geRateLimit() const +{ + return rate_limit; +} + +const string & +AccessControlPracticeSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +AccessControlPracticeSpec::getName() const +{ + return practice_name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/appsec_practice_section.cc b/components/security_apps/local_policy_mgmt_gen/appsec_practice_section.cc new file mode 100755 index 0000000..4b90fca --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/appsec_practice_section.cc @@ -0,0 +1,752 @@ +// 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 "appsec_practice_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"}; +static const set valid_confidences = {"medium", "high", "critical"}; + +void +AppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots URI"; + parseAppsecJSONKey("uri", uri, archive_in); +} + +const string & +AppSecWebBotsURI::getURI() const +{ + return uri; +} + +vector +AppSecPracticeAntiBot::getIjectedUris() const +{ + vector injected; + for (const AppSecWebBotsURI &uri : injected_uris) { + injected.push_back(uri.getURI()); + } + return injected; +} + +vector +AppSecPracticeAntiBot::getValidatedUris() const +{ + vector validated; + for (const AppSecWebBotsURI &uri : validated_uris) { + validated.push_back(uri.getURI()); + } + return validated; +} + +void +AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots"; + parseAppsecJSONKey>("injected-URIs", injected_uris, archive_in); + parseAppsecJSONKey>("validated-URIs", validated_uris, archive_in); + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << override_mode; + } +} + +void +AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const +{ + vector injected; + vector validated; + for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + for (const AppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); + out_ar( + cereal::make_nvp("injected", injected), + cereal::make_nvp("validated", validated) + ); +} + +void +AppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Attack Protections"; + parseAppsecJSONKey("csrf-enabled", csrf_protection, archive_in, "inactive"); + parseAppsecJSONKey("error-disclosure-enabled", error_disclosure, archive_in, "inactive"); + parseAppsecJSONKey("open-redirect-enabled", open_redirect, archive_in, "inactive"); + parseAppsecJSONKey("non-valid-http-methods", non_valid_http_methods, archive_in, false); +} + +const string +AppSecWebAttackProtections::getCsrfProtectionMode() const +{ + if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << csrf_protection + << ". Setting CSRF protection to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(csrf_protection); +} + +const string & +AppSecWebAttackProtections::getErrorDisclosureMode() const +{ + return error_disclosure; +} + +bool +AppSecWebAttackProtections::getNonValidHttpMethods() const +{ + return non_valid_http_methods; +} + +const string +AppSecWebAttackProtections::getOpenRedirectMode() const +{ + if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << open_redirect + << ". Setting Open Redirect mode to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(open_redirect); +} + +void +AppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey("protections", protections, archive_in); + parseAppsecJSONKey("override-mode", mode, archive_in, "Unset"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec practice override mode invalid: " << mode; + } + + if (getMode() == "Prevent") { + parseAppsecJSONKey("minimum-confidence", minimum_confidence, archive_in, "critical"); + if (valid_confidences.count(minimum_confidence) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec practice override minimum confidence invalid: " + << minimum_confidence; + } + } else { + minimum_confidence = "Transparent"; + } + parseAppsecJSONKey("max-body-size-kb", max_body_size_kb, archive_in, 1000000); + parseAppsecJSONKey("max-header-size-bytes", max_header_size_bytes, archive_in, 102400); + parseAppsecJSONKey("max-object-depth", max_object_depth, archive_in, 40); + parseAppsecJSONKey("max-url-size-bytes", max_url_size_bytes, archive_in, 32768); +} + +int +AppSecPracticeWebAttacks::getMaxBodySizeKb() const +{ + return max_body_size_kb; +} + +int +AppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const +{ + return max_header_size_bytes; +} + +int +AppSecPracticeWebAttacks::getMaxObjectDepth() const +{ + return max_object_depth; +} + +int +AppSecPracticeWebAttacks::getMaxUrlSizeBytes() const +{ + return max_url_size_bytes; +} + +const string & +AppSecPracticeWebAttacks::getMinimumConfidence() const +{ + return minimum_confidence; +} + +const string & +AppSecPracticeWebAttacks::getMode(const string &default_mode) const +{ + if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) { + dbgError(D_LOCAL_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode; + return default_mode; + } + return key_to_practices_val.at(mode); +} + +void +AppSecPracticeSnortSignatures::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice"; + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); + parseAppsecJSONKey>("configmap", config_map, archive_in); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode; + } +} + +const string & +AppSecPracticeSnortSignatures::getOverrideMode() const +{ + return override_mode; +} + +const vector & +AppSecPracticeSnortSignatures::getConfigMap() const +{ + return config_map; +} + +void +AppSecPracticeOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Practice OpenSchemaAPI practice"; + parseAppsecJSONKey>("configmap", config_map, archive_in); + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Open Schema API override mode invalid: " << override_mode; + } +} + +const string & +AppSecPracticeOpenSchemaAPI::getOverrideMode() const +{ + return override_mode; +} + +const vector & +AppSecPracticeOpenSchemaAPI::getConfigMap() const +{ + return config_map; +} +// LCOV_EXCL_STOP +void +AppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey( + "openapi-schema-validation", + openapi_schema_validation, + archive_in + ); + parseAppsecJSONKey("snort-signatures", snort_signatures, archive_in); + parseAppsecJSONKey("web-attacks", web_attacks, archive_in); + parseAppsecJSONKey("anti-bot", anti_bot, archive_in); + parseAppsecJSONKey("name", practice_name, archive_in); +} + +void +AppSecPracticeSpec::setName(const string &_name) +{ + practice_name = _name; +} + +// LCOV_EXCL_START Reason: no test exist +const AppSecPracticeOpenSchemaAPI & +AppSecPracticeSpec::getOpenSchemaValidation() const +{ + return openapi_schema_validation; +} + +const AppSecPracticeSnortSignatures & +AppSecPracticeSpec::getSnortSignatures() const +{ + return snort_signatures; +} +// LCOV_EXCL_STOP + +const AppSecPracticeWebAttacks & +AppSecPracticeSpec::getWebAttacks() const +{ + return web_attacks; +} + +const AppSecPracticeAntiBot & +AppSecPracticeSpec::getAntiBot() const +{ + return anti_bot; +} + +const string & +AppSecPracticeSpec::getName() const +{ + return practice_name; +} + +void +PracticeAdvancedConfig::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("httpHeaderMaxSize", http_header_max_size), + cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed), + cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size), + cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth), + cereal::make_nvp("urlMaxSize", url_max_size) + ); +} + +void +TriggersInWaapSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("$triggerType", trigger_type), + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("log", log) + ); +} + +ParsedMatch::ParsedMatch(const string &_operator, const string &_tag, const string &_value) + : + operator_type(_operator), + tag(_tag), + value(_value) +{ +} + +// LCOV_EXCL_START Reason: no test exist +ParsedMatch::ParsedMatch(const ExceptionMatch &exceptions) +{ + if (exceptions.getOperator() == "equals") { + operator_type = "basic"; + tag = exceptions.getKey(); + value = exceptions.getValue(); + } else { + operator_type = exceptions.getOperator(); + } + for (const ExceptionMatch &exception_match : exceptions.getMatch()) { + parsed_match.push_back(ParsedMatch(exception_match)); + } +} +// LCOV_EXCL_STOP + +void +ParsedMatch::save(cereal::JSONOutputArchive &out_ar) const +{ + if (parsed_match.size() > 0) { + out_ar(cereal::make_nvp("operator", operator_type)); + int i = 0; + for (const ParsedMatch &operand : parsed_match) { + i++; + out_ar(cereal::make_nvp("operand" + to_string(i), operand)); + } + } else { + out_ar( + cereal::make_nvp("operator", operator_type), + cereal::make_nvp("tag", tag), + cereal::make_nvp("value", value) + ); + } +} + +AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources) +{ + string source_ident = parsed_trusted_sources.getSourceIdent(); + map behavior = {{"httpSourceId", source_ident}}; + parsed_behavior.push_back(behavior); + parsed_match = ParsedMatch("BASIC", "sourceip", "0.0.0.0/0"); +} + +// LCOV_EXCL_START Reason: no test exist +AppSecOverride::AppSecOverride(const InnerException &parsed_exceptions) + : + id(parsed_exceptions.getBehaviorId()), + parsed_match(parsed_exceptions.getMatch()) +{ + map behavior = {{parsed_exceptions.getBehaviorKey(), parsed_exceptions.getBehaviorValue()}}; + parsed_behavior.push_back(behavior); +} +// LCOV_EXCL_STOP + +void +AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const +{ + if (!id.empty()) { + out_ar(cereal::make_nvp("id", id)); + } + out_ar( + cereal::make_nvp("parsedBehavior", parsed_behavior), + cereal::make_nvp("parsedMatch", parsed_match) + ); +} + +void +AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("injected", injected_uris), + cereal::make_nvp("validated", validated_uris) + ); +} + +// LCOV_EXCL_START Reason: no test exist +WebAppSection::WebAppSection( + const string &_application_urls, + const string &_asset_id, + const string &_asset_name, + const string &_rule_id, + const string &_rule_name, + const string &_practice_id, + const string &_practice_name, + const string &_context, + const AppSecPracticeSpec &parsed_appsec_spec, + const LogTriggerSection &parsed_log_trigger, + const string &default_mode, + const AppSecTrustedSources &parsed_trusted_sources, + const vector &parsed_exceptions) + : + application_urls(_application_urls), + asset_id(_asset_id), + asset_name(_asset_name), + rule_id(_rule_id), + rule_name(_rule_name), + practice_id(_practice_id), + practice_name(_practice_name), + context(_context), + web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()), + 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}) +{ + web_attack_mitigation = true; + web_attack_mitigation_action = + web_attack_mitigation_severity == "critical" ? "low" : + web_attack_mitigation_severity == "high" ? "balanced" : + web_attack_mitigation_severity == "medium" ? "high" : + "Error"; + + triggers.push_back(TriggersInWaapSection(parsed_log_trigger)); + for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) { + overrides.push_back(AppSecOverride(source_ident)); + } + + for (const InnerException &exception : parsed_exceptions) { + overrides.push_back(AppSecOverride(exception)); + } +} + +WebAppSection::WebAppSection( + const string &_application_urls, + const string &_asset_id, + const string &_asset_name, + const string &_rule_id, + const string &_rule_name, + const string &_practice_id, + const string &_practice_name, + const string &_context, + const string &_web_attack_mitigation_severity, + const string &_web_attack_mitigation_mode, + const PracticeAdvancedConfig &_practice_advanced_config, + const AppsecPracticeAntiBotSection &_anti_bots, + const LogTriggerSection &parsed_log_trigger, + const AppSecTrustedSources &parsed_trusted_sources) + : + application_urls(_application_urls), + asset_id(_asset_id), + asset_name(_asset_name), + rule_id(_rule_id), + rule_name(_rule_name), + practice_id(_practice_id), + practice_name(_practice_name), + context(_context), + web_attack_mitigation_severity(_web_attack_mitigation_severity), + web_attack_mitigation_mode(_web_attack_mitigation_mode), + practice_advanced_config(_practice_advanced_config), + anti_bots(_anti_bots), + trusted_sources({parsed_trusted_sources}) +{ + web_attack_mitigation = true; + web_attack_mitigation_action = + web_attack_mitigation_severity == "critical" ? "low" : + web_attack_mitigation_severity == "high" ? "balanced" : + web_attack_mitigation_severity == "medium" ? "high" : + "Error"; + + triggers.push_back(TriggersInWaapSection(parsed_log_trigger)); + for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) { + overrides.push_back(AppSecOverride(source_ident)); + } +} +// LCOV_EXCL_STOP + +void +WebAppSection::save(cereal::JSONOutputArchive &out_ar) const +{ + string disabled_str = "Disabled"; + string detect_str = "Detect"; + vector empty_list; + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("webAttackMitigation", web_attack_mitigation), + cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity), + cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action), + cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode), + cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), + cereal::make_nvp("csrfProtection", disabled_str), + cereal::make_nvp("openRedirect", disabled_str), + cereal::make_nvp("errorDisclosure", disabled_str), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("assetName", asset_name), + cereal::make_nvp("ruleId", rule_id), + cereal::make_nvp("ruleName", rule_name), + cereal::make_nvp("schemaValidation", false), + cereal::make_nvp("schemaValidation_v2", disabled_str), + cereal::make_nvp("oas", empty_list), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("applicationUrls", application_urls), + cereal::make_nvp("overrides", overrides), + cereal::make_nvp("trustedSources", trusted_sources), + cereal::make_nvp("waapParameters", empty_list), + cereal::make_nvp("botProtection", false), + cereal::make_nvp("antiBot", anti_bots), + cereal::make_nvp("botProtection_v2", detect_str) + ); +} +// LCOV_EXCL_START Reason: no test exist +void +WebAPISection::save(cereal::JSONOutputArchive &out_ar) const +{ + string disabled_str = "Disabled"; + vector empty_list; + out_ar( + cereal::make_nvp("application_urls", application_urls), + cereal::make_nvp("asset_id", asset_id), + cereal::make_nvp("asset_name", asset_name), + cereal::make_nvp("context", context), + cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), + cereal::make_nvp("practice_id", practice_id), + cereal::make_nvp("practice_name", practice_name), + cereal::make_nvp("ruleId", rule_id), + cereal::make_nvp("ruleName", rule_name), + cereal::make_nvp("schemaValidation", false), + cereal::make_nvp("schemaValidation_v2", disabled_str), + cereal::make_nvp("web_attack_mitigation", web_attack_mitigation), + cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action), + cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity), + cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode), + cereal::make_nvp("oas", empty_list), + cereal::make_nvp("trustedSources", empty_list), + cereal::make_nvp("triggers", empty_list), + cereal::make_nvp("waapParameters", empty_list), + cereal::make_nvp("overrides", empty_list) + ); +} +// LCOV_EXCL_STOP + +void +AppSecRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("WebAPISecurity", webAPIPractices), + cereal::make_nvp("WebApplicationSecurity", webApplicationPractices) + ); +} + +void +AppSecWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar(cereal::make_nvp("WAAP", app_sec_rulebase)); +} + +void +ParsedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec ParsedRule"; + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("triggers", log_triggers, archive_in); + parseAppsecJSONKey>("practices", practices, archive_in); + parseAppsecJSONKey("mode", mode, archive_in); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Parsed Rule mode invalid: " << mode; + } + parseAppsecJSONKey("custom-response", custom_response, archive_in); + parseAppsecJSONKey("source-identifiers", source_identifiers, archive_in); + parseAppsecJSONKey("trusted-sources", trusted_sources, archive_in); + try { + archive_in(cereal::make_nvp("host", host)); + } catch (const cereal::Exception &e) + {} // The default ParsedRule does not hold a host, so no error handling +} + +const vector & +ParsedRule::getExceptions() const +{ + return exceptions; +} + +const vector & +ParsedRule::getLogTriggers() const +{ + return log_triggers; +} + +const vector & +ParsedRule::getPractices() const +{ + return practices; +} + +const string & +ParsedRule::getHost() const +{ + return host; +} + +const string & +ParsedRule::getMode() const +{ + return mode; +} + +void +ParsedRule::setHost(const string &_host) +{ + host = _host; +} + +void +ParsedRule::setMode(const string &_mode) +{ + mode = _mode; +} + +const string & +ParsedRule::getCustomResponse() const +{ + return custom_response; +} + +const string & +ParsedRule::getSourceIdentifiers() const +{ + return source_identifiers; +} + +const string & +ParsedRule::getTrustedSources() const +{ + return trusted_sources; +} + +void +AppsecPolicySpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec"; + parseAppsecJSONKey("default", default_rule, archive_in); + default_rule.setHost("*"); + parseAppsecJSONKey>("specific-rules", specific_rules, archive_in); +} + +const ParsedRule & +AppsecPolicySpec::getDefaultRule() const +{ + return default_rule; +} + +const vector & +AppsecPolicySpec::getSpecificRules() const +{ + return specific_rules; +} + +bool +AppsecPolicySpec::isAssetHostExist(const string &full_url) const +{ + for (const ParsedRule &rule : specific_rules) { + if (rule.getHost() == full_url) return true; + } + return false; +} + +void +AppsecPolicySpec::addSpecificRule(const ParsedRule &_rule) +{ + specific_rules.push_back(_rule); +} + +void +AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Appsec Linux Policy"; + parseAppsecJSONKey("policies", policies, archive_in); + parseAppsecJSONKey>("practices", practices, archive_in); + parseAppsecJSONKey>("log-triggers", log_triggers, archive_in); + parseAppsecJSONKey>("custom-responses", custom_responses, archive_in); + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("trusted-sources", trusted_sources, archive_in); + parseAppsecJSONKey>( + "source-identifiers", + sources_identifiers, + archive_in + ); +} + +const AppsecPolicySpec & +AppsecLinuxPolicy::getAppsecPolicySpec() const +{ + return policies; +} + +const vector & +AppsecLinuxPolicy::getAppSecPracticeSpecs() const +{ + return practices; +} + +const vector & +AppsecLinuxPolicy::getAppsecTriggerSpecs() const +{ + return log_triggers; +} + +const vector & +AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const +{ + return custom_responses; +} + +const vector & +AppsecLinuxPolicy::getAppsecExceptions() const +{ + return exceptions; +} + +const vector & +AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const +{ + return trusted_sources; +} + +const vector & +AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const +{ + return sources_identifiers; +} + +void +AppsecLinuxPolicy::addSpecificRule(const ParsedRule &_rule) +{ + policies.addSpecificRule(_rule); +} diff --git a/components/security_apps/local_policy_mgmt_gen/configmaps.cc b/components/security_apps/local_policy_mgmt_gen/configmaps.cc new file mode 100755 index 0000000..33d4437 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/configmaps.cc @@ -0,0 +1,58 @@ +// 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 "configmaps.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +// LCOV_EXCL_START Reason: no test exist +bool +ConfigMaps::loadJson(const std::string &json) +{ + string modified_json = json; + modified_json.pop_back(); + stringstream in; + in.str(modified_json); + dbgTrace(D_LOCAL_POLICY) << "Loading ConfigMaps data"; + try { + cereal::JSONInputArchive in_ar(in); + in_ar( + cereal::make_nvp("data", data) + ); + } catch (cereal::Exception &e) { + dbgError(D_LOCAL_POLICY) << "Failed to load ConfigMaps JSON. Error: " << e.what(); + return false; + } + return true; +} + +string +ConfigMaps::getFileContent() const +{ + if (data.size()) { + return data.begin()->second; + } + return string(); +} + +string +ConfigMaps::getFileName() const +{ + if (data.size()) { + return data.begin()->first; + } + return string(); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/exceptions_section.cc b/components/security_apps/local_policy_mgmt_gen/exceptions_section.cc new file mode 100755 index 0000000..8ad559c --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/exceptions_section.cc @@ -0,0 +1,418 @@ +// 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 "exceptions_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +// LCOV_EXCL_START Reason: no test exist +using AttributeGetter = function(const AppsecExceptionSpec&)>; +static const vector> attributes = { + {"countryCode", [](const AppsecExceptionSpec& e){ return e.getCountryCode(); }}, + {"countryName", [](const AppsecExceptionSpec& e){ return e.getCountryName(); }}, + {"hostName", [](const AppsecExceptionSpec& e){ return e.getHostName(); }}, + {"paramName", [](const AppsecExceptionSpec& e){ return e.getParamName(); }}, + {"paramValue", [](const AppsecExceptionSpec& e){ return e.getParamValue(); }}, + {"protectionName", [](const AppsecExceptionSpec& e){ return e.getProtectionName(); }}, + {"sourceIdentifier", [](const AppsecExceptionSpec& e){ return e.getSourceIdentifier(); }}, + {"sourceIp", [](const AppsecExceptionSpec& e){ return e.getSourceIp(); }}, + {"url", [](const AppsecExceptionSpec& e){ return e.getUrl(); }} +}; +static const set valid_actions = {"skip", "accept", "drop", "suppressLog"}; +static const unordered_map key_to_action = { + { "accept", "accept"}, + { "drop", "reject"}, + { "skip", "ignore"}, + { "suppressLog", "ignore"} +}; + +void +AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception spec"; + parseAppsecJSONKey("action", action, archive_in, "skip"); + if (valid_actions.count(action) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action; + } + + parseAppsecJSONKey>("countryCode", country_code, archive_in); + if (!country_code.empty()) conditions_number++; + + parseAppsecJSONKey>("countryName", country_name, archive_in); + if (!country_name.empty()) conditions_number++; + + parseAppsecJSONKey>("hostName", host_name, archive_in); + if (!host_name.empty()) conditions_number++; + + parseAppsecJSONKey>("paramName", param_name, archive_in); + if (!param_name.empty()) conditions_number++; + + parseAppsecJSONKey>("paramValue", param_value, archive_in); + if (!param_value.empty()) conditions_number++; + + parseAppsecJSONKey>("protectionName", protection_name, archive_in); + if (!protection_name.empty()) conditions_number++; + + parseAppsecJSONKey>("sourceIdentifier", source_identifier, archive_in); + if (!source_identifier.empty()) conditions_number++; + + parseAppsecJSONKey>("sourceIp", source_ip, archive_in); + if (!source_ip.empty()) conditions_number++; + + parseAppsecJSONKey>("url", url, archive_in); + if (!url.empty()) conditions_number++; +} + +const string & +AppsecExceptionSpec::getAction() const +{ + return action; +} + +const vector & +AppsecExceptionSpec::getCountryCode() const +{ + return country_code; +} + +const vector & +AppsecExceptionSpec::getCountryName() const +{ + return country_name; +} + +const vector & +AppsecExceptionSpec::getHostName() const +{ + return host_name; +} + +const vector & +AppsecExceptionSpec::getParamName() const +{ + return param_name; +} + +const vector & +AppsecExceptionSpec::getParamValue() const +{ + return param_value; +} + +const vector & +AppsecExceptionSpec::getProtectionName() const +{ + return protection_name; +} + +const vector & +AppsecExceptionSpec::getSourceIdentifier() const +{ + return source_identifier; +} + +const vector & +AppsecExceptionSpec::getSourceIp() const +{ + return source_ip; +} + +const vector & +AppsecExceptionSpec::getUrl() const +{ + return url; +} + +bool +AppsecExceptionSpec::isOneCondition() const +{ + return conditions_number == 1; +} + +void +AppsecException::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception"; + parseAppsecJSONKey("name", name, archive_in); + archive_in(CEREAL_NVP(exception_spec)); +} + +void +AppsecException::setName(const string &_name) +{ + name = _name; +} + +const string & +AppsecException::getName() const +{ + return name; +} + +const vector & +AppsecException::getExceptions() const +{ + return exception_spec; +} + +ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception) + : + match_type(MatchType::Operator), + op("and") +{ + bool single_condition = parsed_exception.isOneCondition(); + for (auto &attrib : attributes) { + auto &attrib_name = attrib.first; + auto &attrib_getter = attrib.second; + auto exceptions_value = attrib_getter(parsed_exception); + if (exceptions_value.empty()) continue; + if (single_condition) { + if (exceptions_value.size() == 1) { + match_type = MatchType::Condition; + op = "equals"; + key = attrib_name; + value = exceptions_value; + return; + } else { + match_type = MatchType::Operator; + op = "or"; + for (auto new_value : exceptions_value) { + items.push_back(ExceptionMatch(attrib_name, {new_value})); + } + return; + } + } + items.push_back(ExceptionMatch(attrib_name, exceptions_value)); + } +} + +ExceptionMatch::ExceptionMatch(const std::string &_key, const std::vector &values) +{ + if (values.size() == 1) { + match_type = MatchType::Condition; + op = "equals"; + key = _key; + value = values; + } else { + match_type = MatchType::Operator; + op = "or"; + for (auto new_value : values) { + items.push_back(ExceptionMatch(_key, {new_value})); + } + } +} + +ExceptionMatch::ExceptionMatch(const NewAppsecException &parsed_exception) + : + match_type(MatchType::Operator), + op("and") +{ + if (!parsed_exception.getCountryCode().empty()) { + items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode())); + } + if (!parsed_exception.getCountryName().empty()) { + items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName())); + } + if (!parsed_exception.getHostName().empty()) { + items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName())); + } + if (!parsed_exception.getParamName().empty()) { + items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName())); + } + if (!parsed_exception.getParamValue().empty()) { + items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue())); + } + if (!parsed_exception.getProtectionName().empty()) { + items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName())); + } + if (!parsed_exception.getSourceIdentifier().empty()) { + items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier())); + } + if (!parsed_exception.getSourceIp().empty()) { + items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp())); + } + if (!parsed_exception.getUrl().empty()) { + items.push_back(ExceptionMatch("url", parsed_exception.getUrl())); + } +} + +void +ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const +{ + switch (match_type) { + case (MatchType::Condition): { + string type_str = "condition"; + out_ar( + cereal::make_nvp("key", key), + cereal::make_nvp("op", op), + cereal::make_nvp("type", type_str), + cereal::make_nvp("value", value) + ); + break; + } + case (MatchType::Operator): { + string type_str = "operator"; + out_ar( + cereal::make_nvp("op", op), + cereal::make_nvp("type", type_str), + cereal::make_nvp("items", items) + ); + break; + } + default: { + dbgError(D_LOCAL_POLICY) << "No match for exception match type: " << static_cast(match_type); + } + } +} + +const string & +ExceptionMatch::getOperator() const +{ + return op; +} + +const string & +ExceptionMatch::getKey() const +{ + return key; +} + +const string & +ExceptionMatch::getValue() const +{ + return value[0]; +} + +const vector & +ExceptionMatch::getMatch() const +{ + return items; +} + +ExceptionBehavior::ExceptionBehavior(const string &_value) +{ + key = _value == "suppressLog" ? "log" : "action"; + value = key_to_action.at(_value); + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what(); + } +} + +void +ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("key", key), + cereal::make_nvp("value", value), + cereal::make_nvp("id", id) + ); +} + +const string & +ExceptionBehavior::getBehaviorId() const +{ + return id; +} + +const string & +ExceptionBehavior::getBehaviorKey() const +{ + return key; +} + +const string & +ExceptionBehavior::getBehaviorValue() const +{ + return value; +} + +InnerException::InnerException(ExceptionBehavior _behavior, ExceptionMatch _match) + : + behavior(_behavior), + match(_match) +{ +} + +void +InnerException::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("behavior", behavior), + cereal::make_nvp("match", match) + ); +} + +const string & +InnerException::getBehaviorId() const +{ + return behavior.getBehaviorId(); +} + +const string & +InnerException::getBehaviorKey() const +{ + return behavior.getBehaviorKey(); +} + +const string & +InnerException::getBehaviorValue() const +{ + return behavior.getBehaviorValue(); +} + +const ExceptionMatch & +InnerException::getMatch() const +{ + return match; +} + +ExceptionsRulebase::ExceptionsRulebase( + vector _exceptions) + : + exceptions(_exceptions) +{ + string context_id_str = ""; + for (const InnerException & exception : exceptions) { + string curr_id = "parameterId(" + exception.getBehaviorId() + "), "; + context_id_str += curr_id; + } + context_id_str = context_id_str.substr(0, context_id_str.size() - 2); + context = "Any(" + context_id_str + ")"; +} + +void +ExceptionsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("exceptions", exceptions) + ); +} + +void +ExceptionsWrapper::Exception::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar(cereal::make_nvp("exception", exception)); +} + +void +ExceptionsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", exception_rulebase) + ); +} diff --git a/components/security_apps/local_policy_mgmt_gen/include/access_control_practice.h b/components/security_apps/local_policy_mgmt_gen/include/access_control_practice.h new file mode 100755 index 0000000..b8c263a --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/access_control_practice.h @@ -0,0 +1,192 @@ +// 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 __ACCESS_CONTROL_PRACTICE_H__ +#define __ACCESS_CONTROL_PRACTICE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class RateLimitRulesTriggerSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + RateLimitRulesTriggerSection() {}; + + RateLimitRulesTriggerSection( + const std::string &_id, + const std::string &_name, + const std::string &_type + ) + : + id(_id), + name(_name), + type(_type) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getName() const; + +private: + std::string id; + std::string name; + std::string type;; +}; + +class RateLimitRulesSection +{ +public: + RateLimitRulesSection() {}; + + // LCOV_EXCL_START Reason: no test exist + RateLimitRulesSection( + const int _limit, + const std::string &_id, + const std::string &_uri, + const std::string &_scope, + const std::vector &_triggers + ) + : + limit(_limit), + id(_id), + uri(_uri), + scope(_scope), + triggers(_triggers) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int limit; + std::string id; + std::string uri; + std::string scope; + std::vector triggers; +}; + +class RateLimitSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + RateLimitSection() {}; + // LCOV_EXCL_STOP + + RateLimitSection( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &_mode, + const std::string &_practice_id, + const std::string &_name, + const std::vector &_rules); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getId() const; + const std::string & getName() const; + const std::string & getMode() const; + +private: + std::string context; + std::string mode; + std::string practice_id; + std::string name; + std::vector rules; +}; + +class AccessControlRulebaseSection +{ +public: + AccessControlRulebaseSection() {}; + + AccessControlRulebaseSection(const std::vector &_rate_limit) : rate_limit(_rate_limit) {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector rate_limit; +}; + +class AccessControlRulebaseWrapper +{ +public: + AccessControlRulebaseWrapper() {}; + + AccessControlRulebaseWrapper( + const std::vector &rate_limits + ) + : + rule_base(AccessControlRulebaseSection(rate_limits)) + {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + AccessControlRulebaseSection rule_base; +}; + +class AccessControlRateLimiteRules +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector getTriggers() const; + RateLimitRulesSection createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const; + +private: + int limit; + std::string uri; + std::string unit; + std::string comment; + std::vector triggers; +}; + +class AccessControlRateLimit +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getRules() const; + const std::string & getMode() const; + std::vector createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const; + +private: + std::string mode; + std::vector rules; +}; + +class AccessControlPracticeSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const AccessControlRateLimit & geRateLimit() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + AccessControlRateLimit rate_limit; + std::string appsec_class_name; + std::string practice_name; +}; + +#endif // __ACCESS_CONTROL_PRACTICE_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/appsec_practice_section.h b/components/security_apps/local_policy_mgmt_gen/include/appsec_practice_section.h new file mode 100644 index 0000000..a113c6b --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/appsec_practice_section.h @@ -0,0 +1,486 @@ +// 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 __APPSEC_PRACTICE_SECTION_H__ +#define __APPSEC_PRACTICE_SECTION_H__ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "customized_cereal_map.h" +#include "local_policy_common.h" +#include "triggers_section.h" +#include "exceptions_section.h" +#include "trusted_sources_section.h" +#include "new_practice.h" + +class AppSecWebBotsURI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getURI() const; + +private: + std::string uri; +}; + +class AppSecPracticeAntiBot +{ +public: + std::vector getIjectedUris() const; + std::vector getValidatedUris() const; + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string override_mode; + std::vector injected_uris; + std::vector validated_uris; +}; + +class AppSecWebAttackProtections +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string getCsrfProtectionMode() const; + const std::string & getErrorDisclosureMode() const; + bool getNonValidHttpMethods() const; + const std::string getOpenRedirectMode() const; + +private: + std::string csrf_protection; + std::string open_redirect; + std::string error_disclosure; + bool non_valid_http_methods; +}; + +class AppSecPracticeWebAttacks +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMaxBodySizeKb() const; + int getMaxHeaderSizeBytes() const; + int getMaxObjectDepth() const; + int getMaxUrlSizeBytes() const; + const std::string & getMinimumConfidence() const; + const AppSecWebAttackProtections & getprotections() const; + const std::string & getMode(const std::string &default_mode = "Inactive") const; + +private: + int max_body_size_kb; + int max_header_size_bytes; + int max_object_depth; + int max_url_size_bytes; + std::string mode; + std::string minimum_confidence; + AppSecWebAttackProtections protections; +}; + +class AppSecPracticeSnortSignatures +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; + +private: + std::string override_mode; + std::vector config_map; +}; + +class AppSecPracticeOpenSchemaAPI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; + +private: + std::string override_mode; + std::vector config_map; +}; + +class AppSecPracticeSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const; + const AppSecPracticeSnortSignatures & getSnortSignatures() const; + const AppSecPracticeWebAttacks & getWebAttacks() const; + const AppSecPracticeAntiBot & getAntiBot() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + AppSecPracticeOpenSchemaAPI openapi_schema_validation; + AppSecPracticeSnortSignatures snort_signatures; + AppSecPracticeWebAttacks web_attacks; + AppSecPracticeAntiBot anti_bot; + std::string practice_name; +}; + +class PracticeAdvancedConfig +{ +public: + PracticeAdvancedConfig() {} + + PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec) + : + http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()), + http_illegal_methods_allowed(0), + http_request_body_max_size(parsed_appsec_spec.getWebAttacks().getMaxBodySizeKb()), + json_max_object_depth(parsed_appsec_spec.getWebAttacks().getMaxObjectDepth()), + url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes()) + {} + + // LCOV_EXCL_START Reason: no test exist + PracticeAdvancedConfig( + int _http_header_max_size, + int _http_request_body_max_size, + int _json_max_object_depth, + int _url_max_size) + : + http_header_max_size(_http_header_max_size), + http_illegal_methods_allowed(0), + http_request_body_max_size(_http_request_body_max_size), + json_max_object_depth(_json_max_object_depth), + url_max_size(_url_max_size) + {} + // LCOV_EXCL_STOP + + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int http_header_max_size; + int http_illegal_methods_allowed; + int http_request_body_max_size; + int json_max_object_depth; + int url_max_size; +}; + +class TriggersInWaapSection +{ +public: + TriggersInWaapSection(const LogTriggerSection &log_section) + : + trigger_type("log"), + id(log_section.getTriggerId()), + name(log_section.getTriggerName()), + log(log_section) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string trigger_type; + std::string id; + std::string name; + LogTriggerSection log; +}; + +class ParsedMatch +{ +public: + ParsedMatch() {} + ParsedMatch(const std::string &_operator, const std::string &_tag, const std::string &_value); + + ParsedMatch(const ExceptionMatch &exceptions); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string operator_type; + std::string tag; + std::string value; + std::vector parsed_match; +}; + +class AppSecOverride +{ +public: + AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources); + AppSecOverride(const InnerException &parsed_exceptions); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string id; + std::vector> parsed_behavior; + ParsedMatch parsed_match; +}; + +class AppsecPracticeAntiBotSection +{ +public: + AppsecPracticeAntiBotSection() {}; + // LCOV_EXCL_START Reason: no test exist + AppsecPracticeAntiBotSection(const NewAppSecPracticeAntiBot &anti_bot) : + injected_uris(anti_bot.getIjectedUris()), + validated_uris(anti_bot.getValidatedUris()) + {}; + // LCOV_EXCL_STOP + + AppsecPracticeAntiBotSection(const AppSecPracticeAntiBot &anti_bot) : + injected_uris(anti_bot.getIjectedUris()), + validated_uris(anti_bot.getValidatedUris()) + {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector injected_uris; + std::vector validated_uris; +}; + +class WebAppSection +{ +public: + WebAppSection() {} + + WebAppSection( + const std::string &_application_urls, + const std::string &_asset_id, + const std::string &_asset_name, + const std::string &_rule_id, + const std::string &_rule_name, + const std::string &_practice_id, + const std::string &_practice_name, + const std::string &_context, + const AppSecPracticeSpec &parsed_appsec_spec, + const LogTriggerSection &parsed_log_trigger, + const std::string &default_mode, + const AppSecTrustedSources &parsed_trusted_sources, + const std::vector &parsed_exceptions + ); + + WebAppSection( + const std::string &_application_urls, + const std::string &_asset_id, + const std::string &_asset_name, + const std::string &_rule_id, + const std::string &_rule_name, + const std::string &_practice_id, + const std::string &_practice_name, + const std::string &_context, + const std::string &_web_attack_mitigation_severity, + const std::string &_web_attack_mitigation_mode, + const PracticeAdvancedConfig &_practice_advanced_config, + const AppsecPracticeAntiBotSection &_anti_bots, + const LogTriggerSection &parsed_log_trigger, + const AppSecTrustedSources &parsed_trusted_sources); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string application_urls; + std::string asset_id; + std::string asset_name; + std::string rule_id; + std::string rule_name; + std::string practice_id; + std::string practice_name; + std::string context; + std::string web_attack_mitigation_action; + std::string web_attack_mitigation_severity; + std::string web_attack_mitigation_mode; + bool web_attack_mitigation; + std::vector triggers; + PracticeAdvancedConfig practice_advanced_config; + AppsecPracticeAntiBotSection anti_bots; + std::vector trusted_sources; + std::vector overrides; +}; + +class WebAPISection +{ +public: + WebAPISection( + const std::string &_application_urls, + const std::string &_asset_id, + const std::string &_asset_name, + const std::string &_rule_id, + const std::string &_rule_name, + const std::string &_practice_id, + const std::string &_practice_name, + const std::string &_web_attack_mitigation_action, + const std::string &_web_attack_mitigation_severity, + const std::string &_web_attack_mitigation_mode, + bool _web_attack_mitigation, + const PracticeAdvancedConfig &_practice_advanced_config) + : + application_urls(_application_urls), + asset_id(_asset_id), + asset_name(_asset_name), + rule_id(_rule_id), + rule_name(_rule_name), + practice_id(_practice_id), + practice_name(_practice_name), + context("practiceId(" + practice_id +")"), + web_attack_mitigation_action(_web_attack_mitigation_action), + web_attack_mitigation_severity(_web_attack_mitigation_severity), + web_attack_mitigation_mode(_web_attack_mitigation_mode), + web_attack_mitigation(_web_attack_mitigation), + practice_advanced_config(_practice_advanced_config) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string application_urls; + std::string asset_id; + std::string asset_name; + std::string rule_id; + std::string rule_name; + std::string practice_id; + std::string practice_name; + std::string context; + std::string web_attack_mitigation_action; + std::string web_attack_mitigation_severity; + std::string web_attack_mitigation_mode; + bool web_attack_mitigation; + PracticeAdvancedConfig practice_advanced_config; +}; + +class AppSecRulebase +{ +public: + AppSecRulebase( + std::vector _webApplicationPractices, + std::vector _webAPIPractices) + : + webApplicationPractices(_webApplicationPractices), + webAPIPractices(_webAPIPractices) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector webApplicationPractices; + std::vector webAPIPractices; +}; + + +class AppSecWrapper +{ +public: + AppSecWrapper(const AppSecRulebase &_app_sec) + : + app_sec_rulebase(_app_sec) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + AppSecRulebase app_sec_rulebase; +}; + +class ParsedRule +{ +public: + ParsedRule() {} + ParsedRule(const std::string &_host) : host(_host) {} + + void load(cereal::JSONInputArchive &archive_in); + const std::vector & getExceptions() const; + const std::vector & getLogTriggers() const; + const std::vector & getPractices() const; + const std::string & getHost() const; + const std::string & getMode() const; + void setHost(const std::string &_host); + void setMode(const std::string &_mode); + const std::string & getCustomResponse() const; + const std::string & getSourceIdentifiers() const; + const std::string & getTrustedSources() const; + +private: + std::vector exceptions; + std::vector log_triggers; + std::vector practices; + std::string host; + std::string mode; + std::string custom_response; + std::string source_identifiers; + std::string trusted_sources; +}; + +class AppsecPolicySpec : Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const ParsedRule & getDefaultRule() const; + const std::vector & getSpecificRules() const; + bool isAssetHostExist(const std::string &full_url) const; + void addSpecificRule(const ParsedRule &_rule); + +private: + ParsedRule default_rule; + std::vector specific_rules; +}; + +class AppsecLinuxPolicy : Singleton::Consume +{ +public: + AppsecLinuxPolicy() {} + AppsecLinuxPolicy( + const AppsecPolicySpec &_policies, + const std::vector &_practices, + const std::vector &_log_triggers, + const std::vector &_custom_responses, + const std::vector &_exceptions, + const std::vector &_trusted_sources, + const std::vector &_sources_identifiers) + : + policies(_policies), + practices(_practices), + log_triggers(_log_triggers), + custom_responses(_custom_responses), + exceptions(_exceptions), + trusted_sources(_trusted_sources), + sources_identifiers(_sources_identifiers) {} + + void serialize(cereal::JSONInputArchive &archive_in); + + const AppsecPolicySpec & getAppsecPolicySpec() const; + const std::vector & getAppSecPracticeSpecs() const; + const std::vector & getAppsecTriggerSpecs() const; + const std::vector & getAppSecCustomResponseSpecs() const; + const std::vector & getAppsecExceptions() const; + const std::vector & getAppsecTrustedSourceSpecs() const; + const std::vector & getAppsecSourceIdentifierSpecs() const; + void addSpecificRule(const ParsedRule &_rule); + +private: + AppsecPolicySpec policies; + std::vector practices; + std::vector log_triggers; + std::vector custom_responses; + std::vector exceptions; + std::vector trusted_sources; + std::vector sources_identifiers; +}; + +#endif // __APPSEC_PRACTICE_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/configmaps.h b/components/security_apps/local_policy_mgmt_gen/include/configmaps.h new file mode 100755 index 0000000..c289fb0 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/configmaps.h @@ -0,0 +1,41 @@ +// 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 __CONFIGMAPS_H__ +#define __CONFIGMAPS_H__ + +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "cereal/archives/json.hpp" +#include +#include "customized_cereal_map.h" + +#include "local_policy_common.h" + +class ConfigMaps : public ClientRest +{ +public: + bool loadJson(const std::string &json); + + std::string getFileContent() const; + std::string getFileName() const; + +private: + std::map data; +}; + +#endif // __CONFIGMAPS_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/exceptions_section.h b/components/security_apps/local_policy_mgmt_gen/include/exceptions_section.h new file mode 100644 index 0000000..e03ee27 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/exceptions_section.h @@ -0,0 +1,171 @@ +// 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 __EXCEPTPIONS_SECTION_H__ +#define __EXCEPTPIONS_SECTION_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "local_policy_common.h" +#include "new_exceptions.h" + +class AppsecExceptionSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getAction() const; + const std::vector & getCountryCode() const; + const std::vector & getCountryName() const; + const std::vector & getHostName() const; + const std::vector & getParamName() const; + const std::vector & getParamValue() const; + const std::vector & getProtectionName() const; + const std::vector & getSourceIdentifier() const; + const std::vector & getSourceIp() const; + const std::vector & getUrl() const; + bool isOneCondition() const; + +private: + int conditions_number; + std::string action; + std::vector country_code; + std::vector country_name; + std::vector host_name; + std::vector param_name; + std::vector param_value; + std::vector protection_name; + std::vector source_identifier; + std::vector source_ip; + std::vector url; +}; + +class AppsecException +{ +public: + AppsecException() {}; + + // LCOV_EXCL_START Reason: no test exist + AppsecException(const std::string &_name, const std::vector &_exception_spec) + : + name(_name), + exception_spec(_exception_spec) {}; + // LCOV_EXCL_STOP + + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::vector & getExceptions() const; + void setName(const std::string &_name); + +private: + std::string name; + std::vector exception_spec; +}; + +class ExceptionMatch +{ +public: + ExceptionMatch() {} + ExceptionMatch(const AppsecExceptionSpec &parsed_exception); + ExceptionMatch(const std::string &_key, const std::vector &_value); + ExceptionMatch(const NewAppsecException &parsed_exception); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getOperator() const; + const std::string & getKey() const; + const std::string & getValue() const; + const std::vector & getMatch() const; + +private: + MatchType match_type; + std::string key; + std::string op; + std::vector value; + std::vector items; +}; + +class ExceptionBehavior +{ +public: + ExceptionBehavior() {} + ExceptionBehavior(const std::string &_value); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getBehaviorId() const; + const std::string & getBehaviorKey() const; + const std::string & getBehaviorValue() const; + +private: + std::string key; + std::string id; + std::string value; +}; + +class InnerException +{ +public: + InnerException() {} + InnerException(ExceptionBehavior _behavior, ExceptionMatch _match); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getBehaviorId() const; + const std::string & getBehaviorKey() const; + const std::string & getBehaviorValue() const; + const ExceptionMatch & getMatch() const; + +private: + ExceptionBehavior behavior; + ExceptionMatch match; +}; + +class ExceptionsRulebase +{ +public: + ExceptionsRulebase(std::vector _exceptions); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string context; + std::vector exceptions; +}; + +class ExceptionsWrapper +{ +public: + class Exception + { + public: + Exception(const std::vector &_exception) : exception(_exception) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + + private: + std::vector exception; + }; + ExceptionsWrapper(const std::vector &_exception) : exception_rulebase(Exception(_exception)) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + Exception exception_rulebase; +}; +#endif // __EXCEPTPIONS_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/ingress_data.h b/components/security_apps/local_policy_mgmt_gen/include/ingress_data.h new file mode 100644 index 0000000..16d7e78 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/ingress_data.h @@ -0,0 +1,125 @@ +// 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 __INGRESS_DATA_H__ +#define __INGRESS_DATA_H__ + +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "cereal/archives/json.hpp" +#include +#include "customized_cereal_map.h" + +#include "local_policy_common.h" + +class IngressMetadata +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::map & getAnnotations() const; + +private: + std::string name; + std::string resourceVersion; + std::string namespace_name; + std::map annotations; +}; + +class IngressRulePath +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getPath() const; + +private: + std::string path; +}; + +class IngressRulePathsWrapper +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getRulePaths() const; + +private: + std::vector paths; +}; + +class IngressDefinedRule +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getHost() const; + const IngressRulePathsWrapper & getPathsWrapper() const; + +private: + std::string host; + IngressRulePathsWrapper paths_wrapper; +}; + +class DefaultBackend +{ +public: + void load(cereal::JSONInputArchive &); + +private: + bool is_exists = false; +}; + +class IngressSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getRules() const; + +private: + std::string ingress_class_name; + std::vector rules; + DefaultBackend default_backend; +}; + +class SingleIngressData +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const IngressMetadata & getMetadata() const; + const IngressSpec & getSpec() const; + +private: + IngressMetadata metadata; + IngressSpec spec; +}; + + +class IngressData : public ClientRest +{ +public: + bool loadJson(const std::string &json); + + const std::vector & getItems() const; + +private: + std::string apiVersion; + std::vector items; +}; +#endif // __INGRESS_DATA_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/k8s_policy_utils.h b/components/security_apps/local_policy_mgmt_gen/include/k8s_policy_utils.h new file mode 100644 index 0000000..99cefc2 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/k8s_policy_utils.h @@ -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. + +#ifndef __K8S_POLICY_UTILS_H__ +#define __K8S_POLICY_UTILS_H__ + +#include +#include +#include +#include + +#include + +#include "maybe_res.h" +#include "i_orchestration_tools.h" +#include "i_shell_cmd.h" +#include "i_messaging.h" +#include "i_env_details.h" +#include "i_agent_details.h" +#include "appsec_practice_section.h" +#include "new_appsec_linux_policy.h" +#include "policy_maker_utils.h" + +enum class AnnotationKeys { PolicyKey, OpenAppsecIo, SyslogAddressKey, SyslogPortKey, ModeKey }; + +class K8sPolicyUtils + : + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume +{ +public: + void init(); + + std::tuple, std::map> + createAppsecPoliciesFromIngresses(); + void getClusterId() const; + +private: + std::map parseIngressAnnotations( + const std::map &annotations + ) const; + + template + Maybe getObjectFromCluster(const std::string &path) const; + + std::map> extractElementsNames( + const std::vector &specific_rules, + const ParsedRule &default_rule + ) const; + + std::map> extractElementsNamesV1beta2( + const std::vector &specific_rules, + const NewParsedRule &default_rule + ) const; + + std::vector extractExceptionsFromCluster( + const std::string &crd_plural, + const std::unordered_set &elements_names + ) const; + + template + std::vector extractElementsFromCluster( + const std::string &crd_plural, + const std::unordered_set &elements_names + ) const; + + void createSnortFile(std::vector &practices) const; + + template + std::vector extractV1Beta2ElementsFromCluster( + const std::string &crd_plural, + const std::unordered_set &elements_names + ) const; + + Maybe createAppsecPolicyK8sFromV1beta1Crds( + const AppsecSpecParser &appsec_policy_spe, + const std::string &ingress_mode + ) const; + + Maybe createAppsecPolicyK8sFromV1beta2Crds( + const AppsecSpecParser &appsec_policy_spe, + const std::string &ingress_mode + ) const; + + template + void createPolicy( + T &appsec_policy, + std::map &policies, + std::map &annotations_values, + const SingleIngressData &item) const; + + std::tuple, Maybe> createAppsecPolicyK8s( + const std::string &policy_name, + const std::string &ingress_mode + ) const; + + I_EnvDetails* env_details = nullptr; + I_Messaging* messaging = nullptr; + EnvType env_type; + Flags conn_flags; + std::string token; +}; + +#endif // __K8S_POLICY_UTILS_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/local_policy_common.h b/components/security_apps/local_policy_mgmt_gen/include/local_policy_common.h new file mode 100644 index 0000000..2ef8b31 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/local_policy_common.h @@ -0,0 +1,144 @@ +// 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 __LOCAL_POLICY_COMMON_H__ +#define __LOCAL_POLICY_COMMON_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "cereal/archives/json.hpp" +#include +#include "customized_cereal_map.h" + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +enum class PracticeType { WebApplication, WebAPI, RateLimit }; +enum class TriggerType { Log, WebUserResponse }; +enum class MatchType { Condition, Operator }; + +static const std::unordered_map string_to_match_type = { + { "condition", MatchType::Condition }, + { "operator", MatchType::Operator } +}; + +static const std::unordered_map string_to_practice_type = { + { "WebApplication", PracticeType::WebApplication }, + { "WebAPI", PracticeType::WebAPI }, + { "RateLimit", PracticeType::RateLimit } +}; + +static const std::unordered_map string_to_trigger_type = { + { "log", TriggerType::Log }, + { "WebUserResponse", TriggerType::WebUserResponse } +}; + +static const std::unordered_map key_to_practices_val = { + { "prevent-learn", "Prevent"}, + { "detect-learn", "Detect"}, + { "prevent", "Prevent"}, + { "detect", "Detect"}, + { "inactive", "Inactive"} +}; + +template +void +parseAppsecJSONKey( + const std::string &key_name, + T &value, + cereal::JSONInputArchive &archive_in, + const T &default_value = T()) +{ + try { + archive_in(cereal::make_nvp(key_name, value)); + } catch (const cereal::Exception &e) { + archive_in.setNextName(nullptr); + value = default_value; + dbgDebug(D_LOCAL_POLICY) + << "Could not parse the required key. Key: " + << key_name + << ", Error: " + << e.what(); + } +} + +class AppsecSpecParserMetaData +{ +public: + void + load(cereal::JSONInputArchive &archive_in) + { + dbgTrace(D_LOCAL_POLICY) << "AppsecSpecParserMetaData load"; + parseAppsecJSONKey>("annotations", annotations, archive_in); + } + + const std::map & + getAnnotations() const + { + return annotations; + } + +private: + std::map annotations; +}; + +template +class AppsecSpecParser : public ClientRest +{ +public: + AppsecSpecParser() = default; + AppsecSpecParser(const T &_spec) : spec(_spec) {} + + bool + loadJson(const std::string &json) + { + std::string modified_json = json; + modified_json.pop_back(); + std::stringstream ss; + ss.str(modified_json); + try { + cereal::JSONInputArchive in_ar(ss); + in_ar(cereal::make_nvp("spec", spec)); + in_ar(cereal::make_nvp("metadata", meta_data)); + } catch (cereal::Exception &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to load spec JSON. Error: " << e.what(); + return false; + } + return true; + } + + void + setName(const std::string &_name) + { + spec.setName(_name); + } + + const AppsecSpecParserMetaData & + getMetaData() const + { + return meta_data; + } + + const T & getSpec() const { return spec; } + +private: + T spec; + AppsecSpecParserMetaData meta_data; +}; + +#endif // __LOCAL_POLICY_COMMON_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_appsec_linux_policy.h b/components/security_apps/local_policy_mgmt_gen/include/new_appsec_linux_policy.h new file mode 100755 index 0000000..5b93901 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_appsec_linux_policy.h @@ -0,0 +1,84 @@ +// 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_APPSEC_LINUX_POLICY_H__ +#define __NEW_APPSEC_LINUX_POLICY_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "customized_cereal_map.h" +#include "new_appsec_policy_crd_parser.h" +#include "new_custom_response.h" +#include "new_exceptions.h" +#include "new_log_trigger.h" +#include "new_practice.h" +#include "access_control_practice.h" +#include "new_trusted_sources.h" + + +class V1beta2AppsecLinuxPolicy : Singleton::Consume +{ +public: + // LCOV_EXCL_START Reason: no test exist + V1beta2AppsecLinuxPolicy() {} + + V1beta2AppsecLinuxPolicy( + const NewAppsecPolicySpec &_policies, + const std::vector &_threat_prevention_practices, + const std::vector &_access_control_practices, + const std::vector &_log_triggers, + const std::vector &_custom_responses, + const std::vector &_exceptions, + const std::vector &_trusted_sources, + const std::vector &_sources_identifiers) + : + policies(_policies), + threat_prevection_practices(_threat_prevention_practices), + access_control_practices(_access_control_practices), + log_triggers(_log_triggers), + custom_responses(_custom_responses), + exceptions(_exceptions), + trusted_sources(_trusted_sources), + sources_identifiers(_sources_identifiers) {} + // LCOV_EXCL_STOP + + const NewAppsecPolicySpec & getAppsecPolicySpec() const; + const std::vector & getAppSecPracticeSpecs() const; + const std::vector & getAccessControlPracticeSpecs() const; + const std::vector & getAppsecTriggerSpecs() const; + const std::vector & getAppSecCustomResponseSpecs() const; + const std::vector & getAppsecExceptions() const; + const std::vector & getAppsecTrustedSourceSpecs() const; + const std::vector & getAppsecSourceIdentifierSpecs() const; + void addSpecificRule(const NewParsedRule &_rule); + +private: + NewAppsecPolicySpec policies; + std::vector threat_prevection_practices; + std::vector access_control_practices; + std::vector log_triggers; + std::vector custom_responses; + std::vector exceptions; + std::vector trusted_sources; + std::vector sources_identifiers; +}; + +#endif // __NEW_APPSEC_LINUX_POLICY_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h b/components/security_apps/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h new file mode 100755 index 0000000..db80891 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h @@ -0,0 +1,82 @@ +// 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_APPSEC_POLICY_CRD_PARSER_H__ +#define __NEW_APPSEC_POLICY_CRD_PARSER_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "local_policy_common.h" + +// LCOV_EXCL_START Reason: no test exist + +class NewParsedRule +{ +public: + NewParsedRule() {} + NewParsedRule(const std::string &_host) : host(_host) {} + + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getLogTriggers() const; + const std::vector & getExceptions() const; + const std::vector & getPractices() const; + const std::vector & getAccessControlPractices() const; + const std::string & getSourceIdentifiers() const; + const std::string & getCustomResponse() const; + const std::string & getTrustedSources() const; + const std::string & getHost() const; + const std::string & getMode() const; + + void setHost(const std::string &_host); + void setMode(const std::string &_mode); + +private: + std::vector log_triggers; + std::vector exceptions; + std::vector threat_prevention_practices; + std::vector access_control_practices; + std::string source_identifiers; + std::string custom_response; + std::string trusted_sources; + std::string host; + std::string mode; +}; + +class NewAppsecPolicySpec : Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const NewParsedRule & getDefaultRule() const; + const std::vector & getSpecificRules() const; + const std::string & getAppSecClassName() const; + bool isAssetHostExist(const std::string &full_url) const; + void addSpecificRule(const NewParsedRule &_rule); + +private: + std::string appsec_class_name; + NewParsedRule default_rule; + std::vector specific_rules; +}; + + +#endif // __NEW_APPSEC_POLICY_CRD_PARSER_H__ +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_custom_response.h b/components/security_apps/local_policy_mgmt_gen/include/new_custom_response.h new file mode 100755 index 0000000..2902f5c --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_custom_response.h @@ -0,0 +1,51 @@ +// 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_CUSTOM_RESPONSE_H__ +#define __NEW_CUSTOM_RESPONSE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class NewAppSecCustomResponse +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getHttpResponseCode() const; + const std::string & getMessageBody() const; + const std::string & getMessageTitle() const; + const std::string & getAppSecClassName() const; + const std::string & getMode() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + bool redirect_add_x_event_id; + int http_response_code; + std::string appsec_class_name; + std::string redirect_url; + std::string message_title; + std::string message_body; + std::string mode; + std::string name; +}; + +#endif // __NEW_CUSTOM_RESPONSE_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_exceptions.h b/components/security_apps/local_policy_mgmt_gen/include/new_exceptions.h new file mode 100755 index 0000000..9cc22db --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_exceptions.h @@ -0,0 +1,67 @@ +// 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_EXCEPTIONS_H__ +#define __NEW_EXCEPTIONS_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "local_policy_common.h" + +class NewAppsecExceptionCondition +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getKey() const; + const std::string & getvalue() const; + +private: + std::string key; + std::string value; +}; + +class NewAppsecException +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAction() const; + const std::string & getAppSecClassName() const; + const std::vector getCountryCode() const; + const std::vector getCountryName() const; + const std::vector getHostName() const; + const std::vector getParamName() const; + const std::vector getParamValue() const; + const std::vector getProtectionName() const; + const std::vector getSourceIdentifier() const; + const std::vector getSourceIp() const; + const std::vector getUrl() const; + void setName(const std::string &_name); + +private: + std::string appsec_class_name; + std::string name; + std::string action; + std::vector conditions; +}; + +#endif // __NEW_EXCEPTIONS_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_log_trigger.h b/components/security_apps/local_policy_mgmt_gen/include/new_log_trigger.h new file mode 100755 index 0000000..8e36138 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_log_trigger.h @@ -0,0 +1,172 @@ +// 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_LOG_TRIGGERS_H__ +#define __NEW_LOG_TRIGGERS_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" +#include "i_agent_details.h" +#include "i_env_details.h" + +class NewAppsecTriggerAccessControlLogging +{ +public: + void load(cereal::JSONInputArchive &archive_in); + +private: + bool allow_events = false; + bool drop_events = false; +}; + +class NewAppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isEnabled() const; + bool isResponseBody() const; + const std::string & getMinimumSeverity() const; + +private: + bool enabled = true; + bool response_body = false; + bool response_code = false; + std::string minimum_severity = "high"; +}; + +class NewAppsecTriggerLogging : public ClientRest +{ +public: + void + load(cereal::JSONInputArchive &archive_in); + + bool isAllWebRequests() const; + bool isDetectEvents() const; + bool isPreventEvents() const; + +private: + bool all_web_requests = false; + bool detect_events = false; + bool prevent_events = true; +}; + +class NewAppsecTriggerExtendedLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isHttpHeaders() const; + bool isRequestBody() const; + bool isUrlPath() const; + bool isUrlQuery() const; + +private: + bool http_headers = false; + bool request_body = false; + bool url_path = false; + bool url_query = false; +}; + +class NewLoggingService +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getAddress() const; + int getPort() const; + +private: + std::string address; + std::string proto; + int port = 514; +}; + +class NewStdoutLogging +{ +public: + // LCOV_EXCL_START Reason: no test exist + NewStdoutLogging() : format("json") {} + // LCOV_EXCL_STOP + + void load(cereal::JSONInputArchive &archive_in); + const std::string & getFormat() const; + +private: + std::string format; +}; + +class NewAppsecTriggerLogDestination + : + public ClientRest, + Singleton::Consume, + Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getCefServerUdpPort() const; + int getSyslogServerUdpPort() const; + bool isAgentLocal() const; + bool shouldBeautifyLogs() const; + + bool getCloud() const; + bool isK8SNeeded() const; + bool isCefNeeded() const; + bool isSyslogNeeded() const; + const std::string & getSyslogServerIpv4Address() const; + const std::string & getCefServerIpv4Address() const; + +private: + const NewLoggingService & getSyslogServiceData() const; + const NewLoggingService & getCefServiceData() const; + + bool cloud = false; + bool k8s_service = false; + bool agent_local = true; + bool beautify_logs = true; + NewLoggingService syslog_service; + NewLoggingService cef_service; +}; + +class NewAppsecLogTrigger +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAppSecClassName() const; + void setName(const std::string &_name); + const NewAppsecTriggerAdditionalSuspiciousEventsLogging & + getAppsecTriggerAdditionalSuspiciousEventsLogging() const; + const NewAppsecTriggerLogging & getAppsecTriggerLogging() const; + const NewAppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const; + const NewAppsecTriggerLogDestination & getAppsecTriggerLogDestination() const; + +private: + NewAppsecTriggerAccessControlLogging access_control_logging; + NewAppsecTriggerAdditionalSuspiciousEventsLogging additional_suspicious_events_logging; + NewAppsecTriggerLogging appsec_logging; + NewAppsecTriggerExtendedLogging extended_logging; + NewAppsecTriggerLogDestination log_destination; + std::string name; + std::string appsec_class_name; +}; + +#endif // __NEW_LOG_TRIGGERS_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_practice.h b/components/security_apps/local_policy_mgmt_gen/include/new_practice.h new file mode 100755 index 0000000..c9f6375 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_practice.h @@ -0,0 +1,589 @@ +// 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_PRACTICE_H__ +#define __NEW_PRACTICE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class IpsProtectionsRulesSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IpsProtectionsRulesSection() {}; + + IpsProtectionsRulesSection( + const int _protections_from_year, + const std::string &_action, + const std::string &_confidence_level, + const std::string &_performance_impact, + const std::string &_source_identifier, + const std::string &_severity_level + ) + : + protections_from_year(_protections_from_year), + action(_action), + confidence_level(_confidence_level), + performance_impact(_performance_impact), + source_identifier(_source_identifier), + severity_level(_severity_level) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int protections_from_year; + std::string action; + std::string confidence_level; + std::string performance_impact; + std::string source_identifier; + std::string severity_level; +}; + +class IpsProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IpsProtectionsSection() {}; + // LCOV_EXCL_STOP + + IpsProtectionsSection( + const std::string &_context, + const std::string &asset_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_source_identifier, + const std::string &_mode, + const std::vector &_rules); + + std::string & getMode(); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string context; + std::string name; + std::string asset_id; + std::string practice_name; + std::string practice_id; + std::string source_identifier; + std::string mode; + std::vector rules; +}; + +class IPSSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IPSSection() {}; + + IPSSection(const std::vector &_ips) : ips(_ips) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector ips; +}; + +class IntrusionPreventionWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + IntrusionPreventionWrapper() {}; + + IntrusionPreventionWrapper(const std::vector &_ips) : ips(IPSSection(_ips)) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + IPSSection ips; +}; + +class NewIntrusionPrevention +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + std::vector createIpsRules() const; + const std::string & getMode() const; + +private: + std::string override_mode; + std::string max_performance_impact; + std::string min_severity_level; + std::string high_confidence_event_action; + std::string medium_confidence_event_action; + std::string low_confidence_event_action; + int min_cve_Year; +}; + +class FileSecurityProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecurityProtectionsSection() {}; + // LCOV_EXCL_STOP + + FileSecurityProtectionsSection( + int _file_size_limit, + int _archive_file_size_limit, + bool _allow_files_without_name, + bool _required_file_size_limit, + bool _required_archive_extraction, + const std::string &_context, + const std::string &_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_action, + const std::string &_files_without_name_action, + const std::string &_high_confidence_action, + const std::string &_medium_confidence_action, + const std::string &_low_confidence_action, + const std::string &_severity_level, + const std::string &_file_size_limit_action, + const std::string &_multi_level_archive_action, + const std::string &_unopened_archive_action + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int file_size_limit; + int archive_file_size_limit; + bool allow_files_without_name; + bool required_file_size_limit; + bool required_archive_extraction; + std::string context; + std::string name; + std::string asset_id; + std::string practice_name; + std::string practice_id; + std::string action; + std::string files_without_name_action; + std::string high_confidence_action; + std::string medium_confidence_action; + std::string low_confidence_action; + std::string severity_level; + std::string file_size_limit_action; + std::string file_size_limit_unit; + std::string scan_max_file_size_unit; + std::string multi_level_archive_action; + std::string unopened_archive_action; +}; + +class FileSecuritySection +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecuritySection() {}; + + FileSecuritySection(const std::vector &_file_security) + : + file_security(_file_security) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector file_security; +}; + +class FileSecurityWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecurityWrapper() {}; + + FileSecurityWrapper(const std::vector &_file_security) + : + file_security(FileSecuritySection(_file_security)) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + FileSecuritySection file_security; +}; + +class NewFileSecurityArchiveInspection +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getArchiveFileSizeLimit() const; + bool getrequiredArchiveExtraction() const; + const std::string & getMultiLevelArchiveAction() const; + const std::string & getUnopenedArchiveAction() const; + +private: + int scan_max_file_size; + bool extract_archive_files; + std::string scan_max_file_size_unit; + std::string archived_files_within_archived_files; + std::string archived_files_where_content_extraction_failed; +}; + +class NewFileSecurityLargeFileInspection +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getFileSizeLimit() const; + const std::string & getFileSizeLimitAction() const; + +private: + int file_size_limit; + std::string file_size_limit_unit; + std::string files_exceeding_size_limit_action; +}; + +class NewFileSecurity +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getOverrideMode() const; + const NewFileSecurityArchiveInspection & getArchiveInspection() const; + const NewFileSecurityLargeFileInspection & getLargeFileInspection() const; + FileSecurityProtectionsSection createFileSecurityProtectionsSection( + const std::string &context, + const std::string &asset_name, + const std::string &asset_id, + const std::string &practice_name, + const std::string &practice_id + ) const; + +private: + bool threat_emulation_enabled; + std::string override_mode; + std::string min_severity_level; + std::string high_confidence_event_action; + std::string medium_confidence_event_action; + std::string low_confidence_event_action; + std::string unnamed_files_action; + NewFileSecurityArchiveInspection archive_inspection; + NewFileSecurityLargeFileInspection large_file_inspection; +}; + +class SnortProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + SnortProtectionsSection() {}; + // LCOV_EXCL_STOP + + SnortProtectionsSection( + const std::string &_context, + const std::string &_asset_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_source_identifier, + const std::string &_mode, + const std::vector &_files + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string context; + std::string asset_name; + std::string asset_id; + std::string practice_name; + std::string practice_id; + std::string source_identifier; + std::string mode; + std::vector files; +}; + +class DetectionRules +{ +public: + // LCOV_EXCL_START Reason: no test exist + DetectionRules() {}; + // LCOV_EXCL_STOP + + DetectionRules( + const std::string &_type, + const std::string &_SSM, + const std::string &_keywords, + const std::vector &_context + ); + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string type; + std::string SSM; + std::string keywords; + std::vector context; +}; + +class ProtectionMetadata +{ +public: + // LCOV_EXCL_START Reason: no test exist + ProtectionMetadata() {}; + // LCOV_EXCL_STOP + + ProtectionMetadata( + bool _silent, + const std::string &_protection_name, + const std::string &_severity, + const std::string &_confidence_level, + const std::string &_performance_impact, + const std::string &_last_update, + const std::string &_maintrain_id, + const std::vector &_tags, + const std::vector &_cve_list + ); + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + bool silent; + std::string protection_name; + std::string severity; + std::string confidence_level; + std::string performance_impact; + std::string last_update; + std::string maintrain_id; + std::vector tags; + std::vector cve_list; +}; + +class ProtectionsProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + ProtectionsProtectionsSection() {}; + // LCOV_EXCL_STOP + + ProtectionsProtectionsSection( + const ProtectionMetadata &_protection_metadata, + const DetectionRules &_detection_rules + ); + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + ProtectionMetadata protection_metadata; + DetectionRules detection_rules; +}; + +class ProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + ProtectionsSection() {}; + // LCOV_EXCL_STOP + + ProtectionsSection( + const std::vector &_protections, + const std::string &_name = "", + const std::string &_modification_time = "" + ); + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + const std::vector & getProtections() const; + +private: + std::vector protections; + std::string name; + std::string modification_time; +}; + +class ProtectionsSectionWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + ProtectionsSectionWrapper() {}; + // LCOV_EXCL_STOP + + void serialize(cereal::JSONInputArchive &archive_in); + const std::vector & getProtections() const; + +private: + ProtectionsSection protections; +}; + +class SnortSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + SnortSection() {}; + + SnortSection( + const std::vector &_snort, + const std::vector &_protections) + : + snort_protections(_snort), + protections(_protections) + {}; + // LCOV_EXCL_STOP + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + const std::vector & getProtections() const; + +private: + std::vector snort_protections; + std::vector protections; +}; + +class SnortSectionWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + SnortSectionWrapper() {}; + + SnortSectionWrapper( + const std::vector &_snort, + const std::vector &_protections) + : + snort(SnortSection(_snort, _protections)) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + SnortSection snort; +}; + +class NewSnortSignaturesAndOpenSchemaAPI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + void addFile(const std::string &file_name); + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; + const std::vector & getFiles() const; + +private: + std::string override_mode; + std::vector config_map; + std::vector files; +}; + +class NewAppSecWebBotsURI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getURI() const; + +private: + std::string uri; +}; + +class NewAppSecPracticeAntiBot +{ +public: + std::vector getIjectedUris() const; + std::vector getValidatedUris() const; + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string override_mode; + std::vector injected_uris; + std::vector validated_uris; +}; + +class NewAppSecWebAttackProtections +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string getCsrfProtectionMode() const; + const std::string & getErrorDisclosureMode() const; + bool getNonValidHttpMethods() const; + const std::string getOpenRedirectMode() const; + +private: + std::string csrf_protection; + std::string open_redirect; + std::string error_disclosure; + bool non_valid_http_methods; +}; + +class NewAppSecPracticeWebAttacks +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMaxBodySizeKb() const; + int getMaxHeaderSizeBytes() const; + int getMaxObjectDepth() const; + int getMaxUrlSizeBytes() const; + const std::string & getMinimumConfidence() const; + const NewAppSecWebAttackProtections & getprotections() const; + const std::string & getMode(const std::string &default_mode = "Inactive") const; + +private: + int max_body_size_kb; + int max_header_size_bytes; + int max_object_depth; + int max_url_size_bytes; + std::string mode; + std::string minimum_confidence; + NewAppSecWebAttackProtections protections; +}; + +class NewAppSecPracticeSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + NewSnortSignaturesAndOpenSchemaAPI & getSnortSignatures(); + const NewSnortSignaturesAndOpenSchemaAPI & getOpenSchemaValidation() const; + const NewAppSecPracticeWebAttacks & getWebAttacks() const; + const NewAppSecPracticeAntiBot & getAntiBot() const; + const NewIntrusionPrevention & getIntrusionPrevention() const; + const NewFileSecurity & getFileSecurity() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + NewFileSecurity file_security; + NewIntrusionPrevention intrusion_prevention; + NewSnortSignaturesAndOpenSchemaAPI openapi_schema_validation; + NewSnortSignaturesAndOpenSchemaAPI snort_signatures; + NewAppSecPracticeWebAttacks web_attacks; + NewAppSecPracticeAntiBot anti_bot; + std::string appsec_class_name; + std::string practice_name; +}; + +#endif // __NEW_PRACTICE_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/new_trusted_sources.h b/components/security_apps/local_policy_mgmt_gen/include/new_trusted_sources.h new file mode 100755 index 0000000..9566ced --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/new_trusted_sources.h @@ -0,0 +1,74 @@ +// 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_TRUSTED_SOURCES_H__ +#define __NEW_TRUSTED_SOURCES_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class NewTrustedSourcesSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMinNumOfSources() const; + const std::vector & getSourcesIdentifiers() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + int min_num_of_sources = 0; + std::string name; + std::vector sources_identifiers; + std::string appsec_class_name; +}; + +class Identifier +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getIdentifier() const; + const std::vector & getValues() const; + +private: + std::string identifier; + std::vector value; +}; + +class NewSourcesIdentifiers +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAppSecClassName() const; + const std::vector & getSourcesIdentifiers() const; + void setName(const std::string &_name); + +private: + std::string name; + std::string appsec_class_name; + std::vector sources_identifiers; +}; + +#endif // __NEW_TRUSTED_SOURCES_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h b/components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h new file mode 100755 index 0000000..2436766 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/policy_maker_utils.h @@ -0,0 +1,266 @@ +// 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 __POLICY_MAKER_UTILS_H__ +#define __POLICY_MAKER_UTILS_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "debug.h" +#include "common.h" +#include "maybe_res.h" +#include "i_orchestration_tools.h" +#include "i_shell_cmd.h" +#include "i_messaging.h" +#include "appsec_practice_section.h" +#include "ingress_data.h" +#include "settings_section.h" +#include "triggers_section.h" +#include "local_policy_common.h" +#include "exceptions_section.h" +#include "rules_config_section.h" +#include "trusted_sources_section.h" +#include "new_appsec_linux_policy.h" +#include "access_control_practice.h" + +enum class AnnotationTypes { + PRACTICE, + THREAT_PREVENTION_PRACTICE, + ACCESS_CONTROL_PRACTICE, + TRIGGER, + EXCEPTION, + WEB_USER_RES, + SOURCE_IDENTIFIERS, + TRUSTED_SOURCES, + COUNT +}; + +class SecurityAppsWrapper +{ +public: + SecurityAppsWrapper( + const AppSecWrapper &_waap, + const TriggersWrapper &_trrigers, + const RulesConfigWrapper &_rules, + const IntrusionPreventionWrapper &_ips, + const SnortSectionWrapper &_snort, + const AccessControlRulebaseWrapper &_rate_limit, + const FileSecurityWrapper &_file_security, + const ExceptionsWrapper &_exceptions, + const std::string &_policy_version) + : + waap(_waap), + trrigers(_trrigers), + rules(_rules), + ips(_ips), + snort(_snort), + rate_limit(_rate_limit), + file_security(_file_security), + exceptions(_exceptions), + policy_version(_policy_version) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + AppSecWrapper waap; + TriggersWrapper trrigers; + RulesConfigWrapper rules; + IntrusionPreventionWrapper ips; + SnortSectionWrapper snort; + AccessControlRulebaseWrapper rate_limit; + FileSecurityWrapper file_security; + ExceptionsWrapper exceptions; + std::string policy_version; +}; + +class PolicyWrapper +{ +public: + PolicyWrapper( + const SettingsWrapper &_settings, + const SecurityAppsWrapper &_security_apps) + : + settings(_settings), + security_apps(_security_apps) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + SettingsWrapper settings; + SecurityAppsWrapper security_apps; +}; + +class PolicyMakerUtils + : + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume +{ +public: + std::string proccesSingleAppsecPolicy( + const std::string &policy_path, + const std::string &policy_version, + const std::string &local_appsec_policy_path + ); + + template + std::string proccesMultipleAppsecPolicies( + const std::map &appsec_policies, + const std::string &policy_version, + const std::string &local_appsec_policy_path + ); + +private: + std::string getPolicyName(const std::string &policy_path); + + template + Maybe openFileAsJson(const std::string &path); + + void clearElementsMaps(); + + bool startsWith(const std::string &str, const std::string &prefix); + + bool endsWith(const std::string &str, const std::string &suffix); + + std::tuple splitHostName(const std::string &host_name); + + std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path); + + PolicyWrapper combineElementsToPolicy(const std::string &policy_version); + + void + createIpsSections( + const std::string &asset_id, + const std::string &asset_name, + const std::string &practice_id, + const std::string &practice_name, + const std::string &source_identifier, + const std::string & context, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void createSnortProtecionsSection(const std::string &file_name, const std::string &practic_name); + + void + createSnortSections( + const std::string & context, + const std::string &asset_name, + const std::string &asset_id, + const std::string &practice_name, + const std::string &practice_id, + const std::string &source_identifier, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void + createFileSecuritySections( + const std::string &asset_id, + const std::string &asset_name, + const std::string &practice_id, + const std::string &practice_name, + const std::string & context, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void + createRateLimitSection( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &trigger_id, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void createWebAppSection( + const V1beta2AppsecLinuxPolicy &policy, + const RulesConfigRulebase& rule_config, + const std::string &practice_id, const std::string &full_url, + const std::string &default_mode, + std::map &rule_annotations + ); + + void + createThreatPreventionPracticeSections( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &default_mode, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + template + void createPolicyElementsByRule( + const R &rule, + const R &default_rule, + const T &policy, + const std::string &policy_name + ); + + template + void createPolicyElements( + const std::vector &rules, + const R &default_rule, + const T &policy, + const std::string &policy_name + ); + + template + void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const T &appsec_policy); + + std::map log_triggers; + std::map web_user_res_triggers; + std::map> inner_exceptions; + std::map web_apps; + std::map rules_config; + std::map ips; + std::map snort; + std::map snort_protections; + std::map file_security; + std::map rate_limit; + std::map users_identifiers; + std::map trusted_sources; +}; + +template +std::string +PolicyMakerUtils::proccesMultipleAppsecPolicies( + const std::map &appsec_policies, + const std::string &policy_version, + const std::string &local_appsec_policy_path) +{ + for (const auto &appsec_policy : appsec_policies) { + createAgentPolicyFromAppsecPolicy(appsec_policy.first, appsec_policy.second); + } + + PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version); + return dumpPolicyToFile( + policy_wrapper, + local_appsec_policy_path + ); +} + +#endif // __POLICY_MAKER_UTILS_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/rules_config_section.h b/components/security_apps/local_policy_mgmt_gen/include/rules_config_section.h new file mode 100644 index 0000000..189cff4 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/rules_config_section.h @@ -0,0 +1,190 @@ +// 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 __RULES_CONFIG_SECTION_H__ +#define __RULES_CONFIG_SECTION_H__ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class AssetUrlParser +{ +public: + AssetUrlParser() {} + + static AssetUrlParser parse(const std::string &uri); + std::string query_string, asset_uri, protocol, asset_url, port; +}; + +class PracticeSection +{ +public: + PracticeSection( + const std::string &_id, + const std::string &_type, + const std::string &_practice_name + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string id; + std::string name; + std::string type; +}; + +class ParametersSection +{ +public: + ParametersSection(const std::string &_id, const std::string &_name); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string name; + std::string id; + std::string type = "Exception"; +}; + +class RulesTriggerSection +{ +public: + RulesTriggerSection( + const std::string &_name, + const std::string &_id, + const std::string &_type + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string name; + std::string id; + std::string type; +}; + +class RulesConfigRulebase +{ +public: + RulesConfigRulebase() + {} + + RulesConfigRulebase( + const std::string &_name, + const std::string &_url, + const std::string &_uri, + std::vector _practices, + std::vector _parameters, + std::vector _triggers + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + + const std::string & getAssetName() const; + const std::string & getAssetId() const; + const std::string & getContext() const; + +private: + std::string context; + std::string id; + std::string name; + std::vector practices; + std::vector parameters; + std::vector triggers; +}; + +class UsersIdentifier +{ +public: + UsersIdentifier() {} + + UsersIdentifier( + const std::string &_source_identifier, + std::vector _identifier_values + ); + + const std::string & getIdentifier() const; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string source_identifier; + std::vector identifier_values; +}; + +class UsersIdentifiersRulebase +{ +public: + UsersIdentifiersRulebase() + {} + + UsersIdentifiersRulebase( + const std::string &_context, + const std::string &_source_identifier, + const std::vector &_identifier_values, + const std::vector &_source_identifiers + ); + + const std::string & getIdentifier() const; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string context; + std::string source_identifier; + std::vector identifier_values; + std::vector source_identifiers; +}; + +class RulesRulebase +{ +public: + RulesRulebase( + const std::vector &_rules_config, + const std::vector &_users_identifiers + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + static bool sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second); + static bool sortBySpecificAux(const std::string &first, const std::string &second); + + std::vector rules_config; + std::vector users_identifiers; +}; + +class RulesConfigWrapper +{ +public: + RulesConfigWrapper( + const std::vector &_rules_config, + const std::vector &_users_identifiers) + : + rules_config_rulebase(RulesRulebase(_rules_config, _users_identifiers)) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + RulesRulebase rules_config_rulebase; +}; +#endif // __RULES_CONFIG_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/settings_section.h b/components/security_apps/local_policy_mgmt_gen/include/settings_section.h new file mode 100644 index 0000000..ebbfaee --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/settings_section.h @@ -0,0 +1,68 @@ +// 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 __SETTINGS_SECTION_H__ +#define __SETTINGS_SECTION_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +// LCOV_EXCL_START Reason: no test exist +class AgentSettingsSection +{ +public: + AgentSettingsSection(const std::string &_key, const std::string &_value); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getSettingId() const; + +private: + std::string id; + std::string key; + std::string value; +}; + +class SettingsRulebase +{ +public: + SettingsRulebase(std::vector _agentSettings) : agentSettings(_agentSettings) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector agentSettings; +}; + +class SettingsWrapper +{ +public: + SettingsWrapper(SettingsRulebase _agent); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string profileType = "agent"; + bool isToken = true; + std::string tokenType = "sameToken"; + std::string id; + std::string name = "Kubernetes Agents"; + SettingsRulebase agent; +}; +// LCOV_EXCL_STOP +#endif // __SETTINGS_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/snort_section.h b/components/security_apps/local_policy_mgmt_gen/include/snort_section.h new file mode 100644 index 0000000..6d4c87f --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/snort_section.h @@ -0,0 +1,50 @@ +// 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 __SNORT_SECTION_H__ +#define __SNORT_SECTION_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" + +// LCOV_EXCL_START Reason: no test exist +class AgentSettingsSection +{ +public: + AgentSettingsSection(std::string _key, std::string _value); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string id; + std::string key; + std::string value; +}; + +class IpsSnortSigsRulebase +{ +public: + IpsSnortSigsRulebase(std::vector _agentSettings) : agentSettings(_agentSettings) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector agentSettings; +}; +// LCOV_EXCL_STOP +#endif // __SNORT_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/triggers_section.h b/components/security_apps/local_policy_mgmt_gen/include/triggers_section.h new file mode 100644 index 0000000..5a76463 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/triggers_section.h @@ -0,0 +1,305 @@ +// 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 __TRIGGERS_SECTION_H__ +#define __TRIGGERS_SECTION_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" +#include "i_agent_details.h" +#include "i_env_details.h" + +class LogTriggerSection +{ +public: + LogTriggerSection() + {} + + LogTriggerSection( + const std::string &_name, + const std::string &_verbosity, + const std::string &_extendloggingMinSeverity, + bool _extendlogging, + bool _logToAgent, + bool _logToCef, + bool _logToCloud, + bool _logToK8sService, + bool _logToSyslog, + bool _responseBody, + bool _tpDetect, + bool _tpPrevent, + bool _webBody, + bool _webHeaders, + bool _webRequests, + bool _webUrlPath, + bool _webUrlQuery, + int _cefPortNum, + const std::string &_cefIpAddress, + int _syslogPortNum, + const std::string &_syslogIpAddress, + bool _beautify_logs + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + + const std::string & getTriggerId() const; + const std::string & getTriggerName() const; + +private: + std::string id; + std::string name; + std::string context; + std::string verbosity; + std::string extendloggingMinSeverity; + bool extendlogging; + bool logToAgent; + bool logToCef; + bool logToCloud; + bool logToK8sService; + bool logToSyslog; + bool responseBody; + bool tpDetect; + bool tpPrevent; + bool webBody; + bool webHeaders; + bool webRequests; + bool webUrlPath; + bool webUrlQuery; + int cefPortNum; + std::string cefIpAddress; + int syslogPortNum; + std::string syslogIpAddress; + bool beautify_logs; +}; + +class WebUserResponseTriggerSection +{ +public: + WebUserResponseTriggerSection() {} + + WebUserResponseTriggerSection( + const std::string &_name, + const std::string &_details_level, + const std::string &_response_body, + int _response_code, + const std::string &_response_title + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + + const std::string & getTriggerId() const; + +private: + std::string id; + std::string name; + std::string context; + std::string details_level; + std::string response_body; + std::string response_title; + int response_code; +}; + +class AppSecCustomResponseSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getHttpResponseCode() const; + const std::string & getMessageBody() const; + const std::string & getMessageTitle() const; + const std::string & getMode() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + int httpResponseCode; + std::string messageBody; + std::string messageTitle; + std::string mode; + std::string name; +}; + +class TriggersRulebase +{ +public: + TriggersRulebase( + std::vector _logTriggers, + std::vector _webUserResponseTriggers) + : + logTriggers(_logTriggers), + webUserResponseTriggers(_webUserResponseTriggers) {} + + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector logTriggers; + std::vector webUserResponseTriggers; +}; + +class AppsecTriggerAccessControlLogging +{ +public: + void load(cereal::JSONInputArchive &archive_in); + +private: + bool allow_events = false; + bool drop_events = false; +}; + +class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isEnabled() const; + bool isResponseBody() const; + const std::string & getMinimumSeverity() const; + +private: + bool enabled = true; + bool response_body = false; + std::string minimum_severity = "high"; +}; + +class AppsecTriggerLogging : public ClientRest +{ +public: + void + load(cereal::JSONInputArchive &archive_in); + + bool isAllWebRequests() const; + bool isDetectEvents() const; + bool isPreventEvents() const; + +private: + bool all_web_requests = false; + bool detect_events = false; + bool prevent_events = true; +}; + +class AppsecTriggerExtendedLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isHttpHeaders() const; + bool isRequestBody() const; + bool isUrlPath() const; + bool isUrlQuery() const; + +private: + bool http_headers = false; + bool request_body = false; + bool url_path = false; + bool url_query = false; +}; + +class LoggingService +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getAddress() const; + int getPort() const; + +private: + std::string address; + std::string proto; + int port = 514; +}; + +class StdoutLogging +{ +public: + StdoutLogging() : format("json") {} + + void load(cereal::JSONInputArchive &archive_in); + const std::string & getFormat() const; + +private: + std::string format; +}; + +class AppsecTriggerLogDestination + : + public ClientRest, + Singleton::Consume, + Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getCefServerUdpPort() const; + int getSyslogServerUdpPort() const; + bool isAgentLocal() const; + bool shouldBeautifyLogs() const; + + bool getCloud() const; + bool isK8SNeeded() const; + bool isCefNeeded() const; + bool isSyslogNeeded() const; + const std::string & getSyslogServerIpv4Address() const; + const std::string & getCefServerIpv4Address() const; + +private: + const LoggingService & getSyslogServiceData() const; + const LoggingService & getCefServiceData() const; + + bool cloud = false; + bool k8s_service = false; + bool agent_local = true; + bool beautify_logs = true; + LoggingService syslog_service; + LoggingService cef_service; +}; + +class AppsecTriggerSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + void setName(const std::string &_name); + const AppsecTriggerAdditionalSuspiciousEventsLogging & getAppsecTriggerAdditionalSuspiciousEventsLogging() const; + const AppsecTriggerLogging & getAppsecTriggerLogging() const; + const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const; + const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const; + +private: + AppsecTriggerAccessControlLogging access_control_logging; + AppsecTriggerAdditionalSuspiciousEventsLogging additional_suspicious_events_logging; + AppsecTriggerLogging appsec_logging; + AppsecTriggerExtendedLogging extended_logging; + AppsecTriggerLogDestination log_destination; + std::string name; +}; + +class TriggersWrapper +{ +public: + TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + TriggersRulebase triggers_rulebase; +}; +#endif // __TRIGGERS_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/include/trusted_sources_section.h b/components/security_apps/local_policy_mgmt_gen/include/trusted_sources_section.h new file mode 100755 index 0000000..09f1dcc --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/include/trusted_sources_section.h @@ -0,0 +1,108 @@ +// 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 __TRUSTED_SOURCES_SECTION_H__ +#define __TRUSTED_SOURCES_SECTION_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class TrustedSourcesSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMinNumOfSources() const; + const std::vector & getSourcesIdentifiers() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + int min_num_of_sources = 0; + std::string name; + std::vector sources_identifiers; +}; + +class SourcesIdentifiers +{ +public: + SourcesIdentifiers(const std::string &_source_identifier, const std::string &_value) + : + source_identifier(_source_identifier), + value(_value) + {} + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getSourceIdent() const; + +private: + std::string source_identifier; + std::string value; +}; + +class SourceIdentifierSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getSourceIdentifier() const; + const std::vector & getValues() const; + +private: + std::string source_identifier; + std::vector value; +}; + +class SourceIdentifierSpecWrapper +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::vector & getIdentifiers() const; + void setName(const std::string &_name); + +private: + std::string name; + std::vector identifiers; +}; + +class AppSecTrustedSources +{ +public: + AppSecTrustedSources() + {} + + AppSecTrustedSources( + const std::string &_name, + int _num_of_sources, + const std::vector &_sources_identifiers + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::vector & getSourcesIdentifiers() const; + +private: + std::string id; + std::string name; + int num_of_sources = 0; + std::vector sources_identifiers; +}; +#endif // __TRUSTED_SOURCES_SECTION_H__ diff --git a/components/security_apps/local_policy_mgmt_gen/ingress_data.cc b/components/security_apps/local_policy_mgmt_gen/ingress_data.cc new file mode 100755 index 0000000..8be6f1d --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/ingress_data.cc @@ -0,0 +1,149 @@ +// 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 "ingress_data.h" +#include "customized_cereal_map.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +void +IngressMetadata::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "IngressMetadata load"; + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("resourceVersion", resourceVersion, archive_in); + parseAppsecJSONKey("namespace", namespace_name, archive_in); + parseAppsecJSONKey>("annotations", annotations, archive_in); +} + +const map & +IngressMetadata::getAnnotations() const +{ + return annotations; +} + +void +IngressRulePath::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading ingress defined rule path"; + parseAppsecJSONKey("path", path, archive_in); +} + +const string & +IngressRulePath::getPath() const +{ + return path; +} + +void +IngressRulePathsWrapper::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading ingress defined rule path wrapper"; + parseAppsecJSONKey>("paths", paths, archive_in); +} + +const vector & +IngressRulePathsWrapper::getRulePaths() const +{ + return paths; +} + +void +IngressDefinedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading ingress defined rule"; + parseAppsecJSONKey("host", host, archive_in); + parseAppsecJSONKey("http", paths_wrapper, archive_in); +} + +const string & +IngressDefinedRule::getHost() const +{ + return host; +} + +const IngressRulePathsWrapper & +IngressDefinedRule::getPathsWrapper() const +{ + return paths_wrapper; +} + +void +DefaultBackend::load(cereal::JSONInputArchive &) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Default Backend"; + is_exists = true; +} + +void +IngressSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading single ingress spec"; + parseAppsecJSONKey("ingressClassName", ingress_class_name, archive_in); + parseAppsecJSONKey>("rules", rules, archive_in); + parseAppsecJSONKey("defaultBackend", default_backend, archive_in); +} + +const vector & +IngressSpec::getRules() const +{ + return rules; +} + +void +SingleIngressData::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading single ingress data"; + parseAppsecJSONKey("metadata", metadata, archive_in); + parseAppsecJSONKey("spec", spec, archive_in); +} + +const IngressMetadata & +SingleIngressData::getMetadata() const +{ + return metadata; +} + +const IngressSpec & +SingleIngressData::getSpec() const +{ + return spec; +} + +bool +IngressData::loadJson(const string &json) +{ + string modified_json = json; + modified_json.pop_back(); + stringstream in; + in.str(modified_json); + dbgTrace(D_LOCAL_POLICY) << "Loading ingress data"; + try { + cereal::JSONInputArchive in_ar(in); + in_ar( + cereal::make_nvp("apiVersion", apiVersion), + cereal::make_nvp("items", items) + ); + } catch (cereal::Exception &e) { + dbgError(D_LOCAL_POLICY) << "Failed to load ingress data JSON. Error: " << e.what(); + return false; + } + return true; +} + +const vector & +IngressData::getItems() const +{ + return items; +} diff --git a/components/security_apps/local_policy_mgmt_gen/k8s_policy_utils.cc b/components/security_apps/local_policy_mgmt_gen/k8s_policy_utils.cc new file mode 100644 index 0000000..976ae85 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/k8s_policy_utils.cc @@ -0,0 +1,587 @@ +// 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 "k8s_policy_utils.h" +#include "configmaps.h" + +using namespace std; + +USE_DEBUG_FLAG(D_NGINX_POLICY); + +string +convertAnnotationKeysTostring(const AnnotationKeys &key) +{ + switch (key) { + case AnnotationKeys::PolicyKey: + return "policy"; + case AnnotationKeys::OpenAppsecIo: + return "openappsec.io/"; + case AnnotationKeys::SyslogAddressKey: + return "syslog"; + case AnnotationKeys::ModeKey: + return "mode"; + default: + return "Irrelevant key"; + } +} + +void +K8sPolicyUtils::init() +{ + env_details = Singleton::Consume::by(); + env_type = env_details->getEnvType(); + if (env_type == EnvType::K8S) { + token = env_details->getToken(); + messaging = Singleton::Consume::by(); + conn_flags.setFlag(MessageConnConfig::SECURE_CONN); + conn_flags.setFlag(MessageConnConfig::IGNORE_SSL_VALIDATION); + } +} + +map +K8sPolicyUtils::parseIngressAnnotations(const map &annotations) const +{ + map annotations_values; + for (const auto &annotation : annotations) { + string annotation_key = annotation.first; + string annotation_val = annotation.second; + if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::OpenAppsecIo)) != string::npos) { + if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::PolicyKey)) != string::npos) { + annotations_values[AnnotationKeys::PolicyKey] = annotation_val; + } else if ( + annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::SyslogAddressKey)) != string::npos + ) { + bool has_port = annotation_val.find(":"); + annotations_values[AnnotationKeys::SyslogAddressKey] = + annotation_val.substr(0, annotation_val.find(":")); + annotations_values[AnnotationKeys::SyslogPortKey] = + has_port ? annotation_val.substr(annotation_val.find(":") + 1) : ""; + } else if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::ModeKey)) != string::npos) { + annotations_values[AnnotationKeys::ModeKey] = annotation_val; + } + } + } + return annotations_values; +} + +template +Maybe +K8sPolicyUtils::getObjectFromCluster(const string &path) const +{ + T object; + bool res = messaging->sendObject( + object, + I_Messaging::Method::GET, + "kubernetes.default.svc", + 443, + conn_flags, + path, + "Authorization: Bearer " + token + "\nConnection: close" + ); + + if (res) return object; + + return genError(string("Was not able to get object form k8s cluser in path: " + path)); +} + +map> +K8sPolicyUtils::extractElementsNames(const vector &specific_rules, const ParsedRule &default_rule) const +{ + map> policy_elements_names; + for (const ParsedRule &specific_rule : specific_rules) { + policy_elements_names[AnnotationTypes::EXCEPTION].insert( + specific_rule.getExceptions().begin(), + specific_rule.getExceptions().end() + ); + policy_elements_names[AnnotationTypes::PRACTICE].insert( + specific_rule.getPractices().begin(), + specific_rule.getPractices().end() + ); + policy_elements_names[AnnotationTypes::TRIGGER].insert( + specific_rule.getLogTriggers().begin(), + specific_rule.getLogTriggers().end() + ); + policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(specific_rule.getCustomResponse()); + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(specific_rule.getSourceIdentifiers()); + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(specific_rule.getTrustedSources()); + } + policy_elements_names[AnnotationTypes::EXCEPTION].insert( + default_rule.getExceptions().begin(), + default_rule.getExceptions().end() + ); + policy_elements_names[AnnotationTypes::PRACTICE].insert( + default_rule.getPractices().begin(), + default_rule.getPractices().end() + ); + policy_elements_names[AnnotationTypes::TRIGGER].insert( + default_rule.getLogTriggers().begin(), + default_rule.getLogTriggers().end() + ); + policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(default_rule.getCustomResponse()); + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(default_rule.getSourceIdentifiers()); + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(default_rule.getTrustedSources()); + + return policy_elements_names; +} + +// LCOV_EXCL_START Reason: no test exist +void +extractElementsFromNewRule( + const NewParsedRule &rule, + map> &policy_elements_names) +{ + policy_elements_names[AnnotationTypes::EXCEPTION].insert( + rule.getExceptions().begin(), + rule.getExceptions().end() + ); + policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE].insert( + rule.getPractices().begin(), + rule.getPractices().end() + ); + policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE].insert( + rule.getAccessControlPractices().begin(), + rule.getAccessControlPractices().end() + ); + policy_elements_names[AnnotationTypes::TRIGGER].insert( + rule.getLogTriggers().begin(), + rule.getLogTriggers().end() + ); + 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()); +} + +map> +K8sPolicyUtils::extractElementsNamesV1beta2( + const vector &specific_rules, + const NewParsedRule &default_rule) const +{ + map> policy_elements_names; + for (const NewParsedRule &specific_rule : specific_rules) { + extractElementsFromNewRule(specific_rule, policy_elements_names); + } + extractElementsFromNewRule(default_rule, policy_elements_names); + + return policy_elements_names; +} + +string +getAppSecClassNameFromCluster() +{ + auto env_res = getenv("appsecClassName"); + if (env_res != nullptr) return env_res; + return ""; +} +// LCOV_EXCL_STOP + +vector +K8sPolicyUtils::extractExceptionsFromCluster( + const string &crd_plural, + const unordered_set &elements_names) const +{ + dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural; + vector elements; + for (const string &element_name : elements_names) { + dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name; + auto maybe_appsec_element = getObjectFromCluster>>( + "/apis/openappsec.io/v1beta1/" + crd_plural + "/" + element_name + ); + + if (!maybe_appsec_element.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec element. type: " + << crd_plural + << ", name: " + << element_name + << ". Error: " + << maybe_appsec_element.getErr(); + continue; + } + + AppsecSpecParser> appsec_element = maybe_appsec_element.unpack(); + elements.push_back(AppsecException(element_name, appsec_element.getSpec())); + } + return elements; +} + +template +vector +K8sPolicyUtils::extractElementsFromCluster( + const string &crd_plural, + const unordered_set &elements_names) const +{ + dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural; + vector elements; + for (const string &element_name : elements_names) { + dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name; + auto maybe_appsec_element = getObjectFromCluster>( + "/apis/openappsec.io/v1beta1/" + crd_plural + "/" + element_name + ); + + if (!maybe_appsec_element.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec element. type: " + << crd_plural + << ", name: " + << element_name + << ". Error: " + << maybe_appsec_element.getErr(); + continue; + } + + AppsecSpecParser appsec_element = maybe_appsec_element.unpack(); + if (appsec_element.getSpec().getName() == "") { + appsec_element.setName(element_name); + } + elements.push_back(appsec_element.getSpec()); + } + return elements; +} + +// LCOV_EXCL_START Reason: no test exist +template +vector +K8sPolicyUtils::extractV1Beta2ElementsFromCluster( + const string &crd_plural, + const unordered_set &elements_names) const +{ + dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural; + vector elements; + for (const string &element_name : elements_names) { + dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name; + auto maybe_appsec_element = getObjectFromCluster>( + "/apis/openappsec.io/v1beta2/" + crd_plural + "/" + element_name + ); + + if (!maybe_appsec_element.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec element. type: " + << crd_plural + << ", name: " + << element_name + << ". Error: " + << maybe_appsec_element.getErr(); + continue; + } + + AppsecSpecParser appsec_element = maybe_appsec_element.unpack(); + if (getAppSecClassNameFromCluster() != "" && + appsec_element.getSpec().getAppSecClassName() != getAppSecClassNameFromCluster()) { + continue; + } + + if (appsec_element.getSpec().getName() == "") { + appsec_element.setName(element_name); + } + elements.push_back(appsec_element.getSpec()); + } + return elements; +} +// LCOV_EXCL_STOP + +Maybe +K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds( + const AppsecSpecParser &appsec_policy_spec, + const string &ingress_mode) const +{ + ParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule(); + vector specific_rules = appsec_policy_spec.getSpec().getSpecificRules(); + + if (!ingress_mode.empty() && default_rule.getMode().empty()) { + default_rule.setMode(ingress_mode); + } + + map> policy_elements_names = extractElementsNames( + specific_rules, + default_rule + ); + + + vector practices = extractElementsFromCluster( + "practices", + policy_elements_names[AnnotationTypes::PRACTICE] + ); + + vector log_triggers = extractElementsFromCluster( + "logtriggers", + policy_elements_names[AnnotationTypes::TRIGGER] + ); + + vector web_user_responses = extractElementsFromCluster( + "customresponses", + policy_elements_names[AnnotationTypes::WEB_USER_RES] + ); + + + vector exceptions = extractExceptionsFromCluster( + "exceptions", + policy_elements_names[AnnotationTypes::EXCEPTION] + ); + + vector source_identifiers = extractElementsFromCluster( + "sourcesidentifiers", + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS] + ); + + vector trusted_sources = extractElementsFromCluster( + "trustedsources", + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES] + ); + + AppsecLinuxPolicy appsec_policy = AppsecLinuxPolicy( + appsec_policy_spec.getSpec(), + practices, + log_triggers, + web_user_responses, + exceptions, + trusted_sources, + source_identifiers + ); + return appsec_policy; +} + +// LCOV_EXCL_START Reason: no test exist +void +K8sPolicyUtils::createSnortFile(vector &practices) const +{ + for (NewAppSecPracticeSpec &practice : practices) { + auto orchestration_tools = Singleton::Consume::by(); + auto path = "/etc/cp/conf/snort/snort_k8s_" + practice.getName() + ".rule"; + bool append_mode = false; + for (const string &config_map : practice.getSnortSignatures().getConfigMap()) + { + auto maybe_configmap = getObjectFromCluster( + "/api/v1/namespaces/default/configmaps/" + config_map + ); + if (!maybe_configmap.ok()) { + dbgWarning(D_LOCAL_POLICY) << "Failed to get configMaps from the cluster."; + continue; + } + string file_content = maybe_configmap.unpack().getFileContent(); + string file_name = maybe_configmap.unpack().getFileName(); + if (!orchestration_tools->writeFile(file_content, path, append_mode)) { + dbgWarning(D_LOCAL_POLICY) << "Failed to update the snort_k8s_rules file."; + continue; + } + append_mode = true; + practice.getSnortSignatures().addFile(file_name); + } + } +} + +Maybe +K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds( + const AppsecSpecParser &appsec_policy_spec, + const string &ingress_mode) const +{ + NewParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule(); + vector specific_rules = appsec_policy_spec.getSpec().getSpecificRules(); + string appsec_class_name = appsec_policy_spec.getSpec().getAppSecClassName(); + + if (getAppSecClassNameFromCluster() != "" && + appsec_class_name != getAppSecClassNameFromCluster()) { + return genError("Unmached appsec class name!"); + } + + if (default_rule.getMode().empty() && !ingress_mode.empty()) { + default_rule.setMode(ingress_mode); + } + + map> policy_elements_names = extractElementsNamesV1beta2( + specific_rules, + default_rule + ); + + vector threat_prevention_practices = + extractV1Beta2ElementsFromCluster( + "threatpreventionpractices", + policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE] + ); + + createSnortFile(threat_prevention_practices); + + vector access_control_practices = + extractV1Beta2ElementsFromCluster( + "accesscontrolpractice", + policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE] + ); + + vector log_triggers = extractV1Beta2ElementsFromCluster( + "logtriggers", + policy_elements_names[AnnotationTypes::TRIGGER] + ); + + vector web_user_responses = extractV1Beta2ElementsFromCluster( + "customresponses", + policy_elements_names[AnnotationTypes::WEB_USER_RES] + ); + + vector exceptions = extractV1Beta2ElementsFromCluster( + "exceptions", + policy_elements_names[AnnotationTypes::EXCEPTION] + ); + + vector source_identifiers = extractV1Beta2ElementsFromCluster( + "sourcesidentifiers", + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS] + ); + + vector trusted_sources = extractV1Beta2ElementsFromCluster( + "trustedsources", + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES] + ); + + V1beta2AppsecLinuxPolicy appsec_policy = V1beta2AppsecLinuxPolicy( + appsec_policy_spec.getSpec(), + threat_prevention_practices, + access_control_practices, + log_triggers, + web_user_responses, + exceptions, + trusted_sources, + source_identifiers + ); + return appsec_policy; +} +// LCOV_EXCL_STOP + +bool +doesVersionExist(const map &annotations, const string &version) +{ + for (auto annotation : annotations) { + if(annotation.second.find(version) != std::string::npos) { + return true; + } + } + return false; +} + +std::tuple, Maybe> +K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const +{ + auto maybe_appsec_policy_spec = getObjectFromCluster>( + "/apis/openappsec.io/v1beta1/policies/" + policy_name + ); + + if (!maybe_appsec_policy_spec.ok() || + !doesVersionExist(maybe_appsec_policy_spec.unpack().getMetaData().getAnnotations(), "v1beta1") + ) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve Appsec policy with crds version: v1beta1, Trying version: v1beta2"; + auto maybe_v1beta2_appsec_policy_spec = getObjectFromCluster>( + "/apis/openappsec.io/v1beta2/policies/" + policy_name + ); + if(!maybe_v1beta2_appsec_policy_spec.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec policy. Error: " + << maybe_v1beta2_appsec_policy_spec.getErr(); + return std::make_tuple( + genError("Failed to retrieve AppSec v1beta1 policy. Error: " + maybe_appsec_policy_spec.getErr()), + genError( + "Failed to retrieve AppSec v1beta2 policy. Error: " + maybe_v1beta2_appsec_policy_spec.getErr())); + } + return std::make_tuple( + genError("There is no v1beta1 policy"), + createAppsecPolicyK8sFromV1beta2Crds(maybe_v1beta2_appsec_policy_spec.unpack(), ingress_mode)); + } + + return std::make_tuple( + createAppsecPolicyK8sFromV1beta1Crds(maybe_appsec_policy_spec.unpack(), ingress_mode), + genError("There is no v1beta2 policy")); +} + +template +void +K8sPolicyUtils::createPolicy( + T &appsec_policy, + map &policies, + map &annotations_values, + const SingleIngressData &item) const +{ + for (const IngressDefinedRule &rule : item.getSpec().getRules()) { + string url = rule.getHost(); + for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) { + if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) { + dbgTrace(D_LOCAL_POLICY) + << "Inserting Host data to the specific asset set:" + << "URL: '" + << url + << "' uri: '" + << uri.getPath() + << "'"; + K ingress_rule = K(url + uri.getPath()); + appsec_policy.addSpecificRule(ingress_rule); + } + } + } + policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy; +} + + +std::tuple, map> +K8sPolicyUtils::createAppsecPoliciesFromIngresses() +{ + dbgFlow(D_LOCAL_POLICY) << "Getting all policy object from Ingresses"; + map v1bet1_policies; + map v1bet2_policies; + auto maybe_ingress = getObjectFromCluster("/apis/networking.k8s.io/v1/ingresses"); + + if (!maybe_ingress.ok()) { + // TBD: Error handling : INXT-31444 + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve K8S Ingress configurations. Error: " + << maybe_ingress.getErr(); + return make_tuple(v1bet1_policies, v1bet2_policies); + } + + + IngressData ingress = maybe_ingress.unpack(); + for (const SingleIngressData &item : ingress.getItems()) { + map annotations_values = parseIngressAnnotations( + item.getMetadata().getAnnotations() + ); + + if (annotations_values[AnnotationKeys::PolicyKey].empty()) { + dbgInfo(D_LOCAL_POLICY) << "No policy was found in this ingress"; + continue; + } + + auto maybe_appsec_policy = createAppsecPolicyK8s( + annotations_values[AnnotationKeys::PolicyKey], + annotations_values[AnnotationKeys::ModeKey] + ); + if (!std::get<0>(maybe_appsec_policy).ok() && !std::get<1>(maybe_appsec_policy).ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to create appsec policy. Error: " + << std::get<1>(maybe_appsec_policy).getErr(); + continue; + } + + if (!std::get<0>(maybe_appsec_policy).ok()) { + auto appsec_policy=std::get<1>(maybe_appsec_policy).unpack(); + createPolicy( + appsec_policy, + v1bet2_policies, + annotations_values, + item); + } else { + auto appsec_policy=std::get<0>(maybe_appsec_policy).unpack(); + createPolicy( + appsec_policy, + v1bet1_policies, + annotations_values, + item); + } + } + return make_tuple(v1bet1_policies, v1bet2_policies); +} diff --git a/components/security_apps/local_policy_mgmt_gen/local_policy_mgmt_gen.cc b/components/security_apps/local_policy_mgmt_gen/local_policy_mgmt_gen.cc new file mode 100644 index 0000000..f246783 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/local_policy_mgmt_gen.cc @@ -0,0 +1,128 @@ +// 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 "local_policy_mgmt_gen.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rest.h" +#include "debug.h" +#include "config.h" +#include "connkey.h" +#include "url_parser.h" +#include "i_agent_details.h" +#include "customized_cereal_map.h" +#include "include/appsec_practice_section.h" +#include "include/ingress_data.h" +#include "include/settings_section.h" +#include "include/triggers_section.h" +#include "include/local_policy_common.h" +#include "include/exceptions_section.h" +#include "include/rules_config_section.h" +#include "include/trusted_sources_section.h" +#include "include/policy_maker_utils.h" +#include "k8s_policy_utils.h" +#include "i_env_details.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +const static string default_local_appsec_policy_path = "/tmp/local_appsec.policy"; +const static string default_local_mgmt_policy_path = "/conf/local_policy.yaml"; + +class LocalPolicyMgmtGenerator::Impl + : + public Singleton::Provide::From, + public Singleton::Consume, + public Singleton::Consume +{ + +public: + void + init() + { + } + + string + parseLinuxPolicy(const string &policy_version, const string &local_policy_path) + { + dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - embedded environment"; + + return policy_maker_utils.proccesSingleAppsecPolicy( + local_policy_path, + policy_version, + default_local_appsec_policy_path + ); + } + + string + parseK8sPolicy(const string &policy_version) + { + dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment"; + + dbgInfo(D_LOCAL_POLICY) << "Initializing K8S policy generator"; + K8sPolicyUtils k8s_policy_utils; + k8s_policy_utils.init(); + + auto appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses(); + if (!std::get<0>(appsec_policies).empty()) { + return policy_maker_utils.proccesMultipleAppsecPolicies( + std::get<0>(appsec_policies), + policy_version, + default_local_appsec_policy_path + ); + } + return policy_maker_utils.proccesMultipleAppsecPolicies( + std::get<1>(appsec_policies), + policy_version, + default_local_appsec_policy_path + ); + } + + string + generateAppSecLocalPolicy(EnvType env_type, const string &policy_version, const string &local_policy_paths) + { + return env_type == EnvType::K8S ? + parseK8sPolicy(policy_version) : parseLinuxPolicy(policy_version, local_policy_paths); + } + +private: + PolicyMakerUtils policy_maker_utils; + +}; + +LocalPolicyMgmtGenerator::LocalPolicyMgmtGenerator() + : + Component("LocalPolicyMgmtGenerator"), + pimpl(make_unique()) {} + +LocalPolicyMgmtGenerator::~LocalPolicyMgmtGenerator() {} + +void +LocalPolicyMgmtGenerator::init() +{ + pimpl->init(); +} diff --git a/components/security_apps/local_policy_mgmt_gen/new_appsec_linux_policy.cc b/components/security_apps/local_policy_mgmt_gen/new_appsec_linux_policy.cc new file mode 100755 index 0000000..24dc962 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_appsec_linux_policy.cc @@ -0,0 +1,72 @@ +// 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_appsec_linux_policy.h" +// LCOV_EXCL_START Reason: no test exist + +using namespace std; + +const NewAppsecPolicySpec & +V1beta2AppsecLinuxPolicy::getAppsecPolicySpec() const +{ + return policies; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppSecPracticeSpecs() const +{ + return threat_prevection_practices; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAccessControlPracticeSpecs() const +{ + return access_control_practices; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecTriggerSpecs() const +{ + return log_triggers; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const +{ + return custom_responses; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecExceptions() const +{ + return exceptions; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const +{ + return trusted_sources; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const +{ + return sources_identifiers; +} + +void +V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule) +{ + policies.addSpecificRule(_rule); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc b/components/security_apps/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc new file mode 100755 index 0000000..4fdc0ef --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc @@ -0,0 +1,154 @@ +// 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_appsec_policy_crd_parser.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"}; + +void +NewParsedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec NewParsedRule"; + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("triggers", log_triggers, archive_in); + parseAppsecJSONKey>("threatPreventionPractices", threat_prevention_practices, archive_in); + parseAppsecJSONKey>("accessControlPractices", access_control_practices, archive_in); + parseAppsecJSONKey("mode", mode, archive_in); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec New Parsed Rule mode invalid: " << mode; + } + parseAppsecJSONKey("customResponse", custom_response, archive_in); + parseAppsecJSONKey("sourceIdentifiers", source_identifiers, archive_in); + parseAppsecJSONKey("trustedSources", trusted_sources, archive_in); + try { + archive_in(cereal::make_nvp("host", host)); + } catch (const cereal::Exception &e) + { + // The default NewParsedRule does not hold a host, so by default it will be * + host = "*"; + } +} + +const vector & +NewParsedRule::getLogTriggers() const +{ + return log_triggers; +} +const vector & + +NewParsedRule::getExceptions() const +{ + return exceptions; +} + +const vector & +NewParsedRule::getPractices() const +{ + return threat_prevention_practices; +} + +const vector & +NewParsedRule::getAccessControlPractices() const +{ + return access_control_practices; +} + +const string & +NewParsedRule::getSourceIdentifiers() const +{ + return source_identifiers; +} + +const string & +NewParsedRule::getCustomResponse() const +{ + return custom_response; +} + +const string & +NewParsedRule::getTrustedSources() const +{ + return trusted_sources; +} + +const string & +NewParsedRule::getHost() const +{ + return host; +} + +const string & +NewParsedRule::getMode() const +{ + return mode; +} + +void +NewParsedRule::setHost(const string &_host) +{ + host = _host; +} + +void +NewParsedRule::setMode(const string &_mode) +{ + mode = _mode; +} + +void +NewAppsecPolicySpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("default", default_rule, archive_in); + parseAppsecJSONKey>("specificRules", specific_rules, archive_in); +} + +const NewParsedRule & +NewAppsecPolicySpec::getDefaultRule() const +{ + return default_rule; +} + +const vector & +NewAppsecPolicySpec::getSpecificRules() const +{ + return specific_rules; +} + +const string & +NewAppsecPolicySpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +bool +NewAppsecPolicySpec::isAssetHostExist(const std::string &full_url) const +{ + for (const NewParsedRule &rule : specific_rules) { + if (rule.getHost() == full_url) return true; + } + return false; +} + +void +NewAppsecPolicySpec::addSpecificRule(const NewParsedRule &_rule) +{ + specific_rules.push_back(_rule); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_custom_response.cc b/components/security_apps/local_policy_mgmt_gen/new_custom_response.cc new file mode 100755 index 0000000..d8f815b --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_custom_response.cc @@ -0,0 +1,99 @@ +// 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_custom_response.h" + +#define MIN_RESPONSE_CODE 100 +#define MAX_RESPOMSE_CODE 599 + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"block-page", "response-code-only", "redirect"}; + +void +NewAppSecCustomResponse::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec web user response spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("httpResponseCode", http_response_code, archive_in, 403); + if (http_response_code < MIN_RESPONSE_CODE || http_response_code > MAX_RESPOMSE_CODE) { + dbgWarning(D_LOCAL_POLICY) << "AppSec web user response code invalid: " << http_response_code; + } + parseAppsecJSONKey("mode", mode, archive_in, "block-page"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec web user response mode invalid: " << mode; + } + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("redirectUrl", redirect_url, archive_in); + parseAppsecJSONKey("redirectAddXEventId", redirect_add_x_event_id, archive_in); + if (mode == "block-page") { + parseAppsecJSONKey( + "messageBody", + message_body, + archive_in, + "Openappsec's Application Security has detected an attack and blocked it." + ); + parseAppsecJSONKey( + "messageTitle", + message_title, + archive_in, + "Attack blocked by web application protection" + ); + } +} + +void +NewAppSecCustomResponse::setName(const string &_name) +{ + name = _name; +} + +int +NewAppSecCustomResponse::getHttpResponseCode() const +{ + return http_response_code; +} + +const string & +NewAppSecCustomResponse::getMessageBody() const +{ + return message_body; +} + +const string & +NewAppSecCustomResponse::getMessageTitle() const +{ + return message_title; +} + +const string & +NewAppSecCustomResponse::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewAppSecCustomResponse::getMode() const +{ + return mode; +} + +const string & +NewAppSecCustomResponse::getName() const +{ + return name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_exceptions.cc b/components/security_apps/local_policy_mgmt_gen/new_exceptions.cc new file mode 100755 index 0000000..115a781 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_exceptions.cc @@ -0,0 +1,187 @@ +// 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_exceptions.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +// LCOV_EXCL_START Reason: no test exist +static const set valid_actions = {"skip", "accept", "drop", "suppressLog"}; + +void +NewAppsecExceptionCondition::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception condition"; + parseAppsecJSONKey("key", key, archive_in); + parseAppsecJSONKey("value", value, archive_in); +} + +const string & +NewAppsecExceptionCondition::getKey() const +{ + return key; +} + +const string & +NewAppsecExceptionCondition::getvalue() const +{ + return value; +} + +void +NewAppsecException::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception"; + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("action", action, archive_in); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + if (valid_actions.count(action) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action; + } + parseAppsecJSONKey>("condition", conditions, archive_in); +} + +void +NewAppsecException::setName(const string &_name) +{ + name = _name; +} + +const string & +NewAppsecException::getName() const +{ + return name; +} + +const string & +NewAppsecException::getAction() const +{ + return action; +} + +const string & +NewAppsecException::getAppSecClassName() const +{ + return appsec_class_name; +} + +const vector +NewAppsecException::getCountryCode() const +{ + vector country_codes; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "countryCode") { + country_codes.push_back(condition.getvalue()); + } + } + return country_codes; +} + +const vector +NewAppsecException::getCountryName() const +{ + vector country_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "countryName") { + country_names.push_back(condition.getvalue()); + } + } + return country_names; +} + +const vector +NewAppsecException::getHostName() const +{ + vector host_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "hostName") { + host_names.push_back(condition.getvalue()); + } + } + return host_names; +} + +const vector +NewAppsecException::getParamName() const +{ + vector param_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "paramName") { + param_names.push_back(condition.getvalue()); + } + } + return param_names; +} + +const vector +NewAppsecException::getParamValue() const +{ + vector param_values; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "paramValue") { + param_values.push_back(condition.getvalue()); + } + } + return param_values; +} + +const vector +NewAppsecException::getProtectionName() const +{ + vector protection_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "protectionName") { + protection_names.push_back(condition.getvalue()); + } + } + return protection_names; +} + +const vector +NewAppsecException::getSourceIdentifier() const +{ + vector source_identifiers; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "sourceIdentifier") { + source_identifiers.push_back(condition.getvalue()); + } + } + return source_identifiers; +} + +const vector +NewAppsecException::getSourceIp() const +{ + vector source_ips; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "sourceIp") { + source_ips.push_back(condition.getvalue()); + } + } + return source_ips; +} + +const vector +NewAppsecException::getUrl() const +{ + vector urls; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "url") { + urls.push_back(condition.getvalue()); + } + } + return urls; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_log_trigger.cc b/components/security_apps/local_policy_mgmt_gen/new_log_trigger.cc new file mode 100755 index 0000000..13dded3 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_log_trigger.cc @@ -0,0 +1,321 @@ +// 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_log_trigger.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_severities = {"high", "critical"}; +static const set valid_protocols = {"tcp", "udp"}; +static const set valid_formats = {"json", "json-formatted"}; + +void +NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging"; + parseAppsecJSONKey("allowEvents", allow_events, archive_in, false); + parseAppsecJSONKey("dropEvents", drop_events, archive_in, false); +} + +void +NewAppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging"; + parseAppsecJSONKey("enabled", enabled, archive_in, true); + parseAppsecJSONKey("responseBody", response_body, archive_in, false); + //the old code didn't parse the responsecode so ask Noam what is the currenct default value for it + parseAppsecJSONKey("responseCode", response_code, archive_in, false); + parseAppsecJSONKey("minSeverity", minimum_severity, archive_in, "high"); + if (valid_severities.count(minimum_severity) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec AppSec Trigger - Additional Suspicious Events Logging minimum severity invalid: " + << minimum_severity; + } +} + +bool +NewAppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const +{ + return enabled; +} + +bool +NewAppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const +{ + return response_body; +} + +const string & +NewAppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const +{ + return minimum_severity; +} + +void +NewAppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Logging"; + parseAppsecJSONKey("detectEvents", detect_events, archive_in, false); + parseAppsecJSONKey("preventEvents", prevent_events, archive_in, true); + parseAppsecJSONKey("allWebRequests", all_web_requests, archive_in, false); +} + +bool +NewAppsecTriggerLogging::isAllWebRequests() const +{ + return all_web_requests; +} + +bool +NewAppsecTriggerLogging::isDetectEvents() const +{ + return detect_events; +} + +bool +NewAppsecTriggerLogging::isPreventEvents() const +{ + return prevent_events; +} + +void +NewAppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Extended Logging"; + parseAppsecJSONKey("httpHeaders", http_headers, archive_in, false); + parseAppsecJSONKey("requestBody", request_body, archive_in, false); + parseAppsecJSONKey("urlPath", url_path, archive_in, false); + parseAppsecJSONKey("urlQuery", url_query, archive_in, false); +} + +bool +NewAppsecTriggerExtendedLogging::isHttpHeaders() const +{ + return http_headers; +} + +bool +NewAppsecTriggerExtendedLogging::isRequestBody() const +{ + return request_body; +} + +bool +NewAppsecTriggerExtendedLogging::isUrlPath() const +{ + return url_path; +} + +bool +NewAppsecTriggerExtendedLogging::isUrlQuery() const +{ + return url_query; +} + +void +NewLoggingService::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("address", address, archive_in); + parseAppsecJSONKey("proto", proto, archive_in); + if (valid_protocols.count(proto) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto; + } + + parseAppsecJSONKey("port", port, archive_in, 514); +} + +const string & +NewLoggingService::getAddress() const +{ + return address; +} + +int +NewLoggingService::getPort() const +{ + return port; +} + + +void +NewStdoutLogging::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("format", format, archive_in, "json"); + if (valid_formats.count(format) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Stdout Logging - format invalid: " << format; + } +} + +const string & +NewStdoutLogging::getFormat() const +{ + return format; +} + +void +NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination"; + // TBD: support "file" + parseAppsecJSONKey("cloud", cloud, archive_in, false); + auto mode = Singleton::Consume::by()->getOrchestrationMode(); + auto env_type = Singleton::Consume::by()->getEnvType(); + bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S); + parseAppsecJSONKey("k8s-service", k8s_service, archive_in, k8s_service_default); + + NewStdoutLogging stdout_log; + parseAppsecJSONKey("stdout", stdout_log, archive_in); + agent_local = !(stdout_log.getFormat().empty()); + beautify_logs = stdout_log.getFormat() == "json-formatted"; + parseAppsecJSONKey("syslogService", syslog_service, archive_in); + parseAppsecJSONKey("cefService", cef_service, archive_in); +} + +int +NewAppsecTriggerLogDestination::getCefServerUdpPort() const +{ + return getCefServiceData().getPort(); +} + +int +NewAppsecTriggerLogDestination::getSyslogServerUdpPort() const +{ + return getSyslogServiceData().getPort(); +} + +bool +NewAppsecTriggerLogDestination::isAgentLocal() const +{ + return agent_local; +} + +bool +NewAppsecTriggerLogDestination::shouldBeautifyLogs() const +{ + return beautify_logs; +} + +bool +NewAppsecTriggerLogDestination::getCloud() const +{ + return cloud; +} + +bool +NewAppsecTriggerLogDestination::isK8SNeeded() const +{ + return k8s_service; +} + +bool +NewAppsecTriggerLogDestination::isCefNeeded() const +{ + return !getCefServiceData().getAddress().empty(); +} + +bool +NewAppsecTriggerLogDestination::isSyslogNeeded() const +{ + return !getSyslogServiceData().getAddress().empty(); +} + +const +string & NewAppsecTriggerLogDestination::getSyslogServerIpv4Address() const +{ + return getSyslogServiceData().getAddress(); +} + +const string & +NewAppsecTriggerLogDestination::getCefServerIpv4Address() const +{ + return getCefServiceData().getAddress(); +} + +const NewLoggingService & +NewAppsecTriggerLogDestination::getSyslogServiceData() const +{ + return syslog_service; +} + +const NewLoggingService & +NewAppsecTriggerLogDestination::getCefServiceData() const +{ + return cef_service; +} + +void +NewAppsecLogTrigger::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec log trigger"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey( + "accessControlLogging", + access_control_logging, + archive_in + ); + parseAppsecJSONKey( + "additionalSuspiciousEventsLogging", + additional_suspicious_events_logging, + archive_in + ); + parseAppsecJSONKey("appsecLogging", appsec_logging, archive_in); + parseAppsecJSONKey("extendedLogging", extended_logging, archive_in); + parseAppsecJSONKey("logDestination", log_destination, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewAppsecLogTrigger::setName(const string &_name) +{ + name = _name; +} + +const string & +NewAppsecLogTrigger::getName() const +{ + return name; +} + +const string & +NewAppsecLogTrigger::getAppSecClassName() const +{ + return appsec_class_name; +} + +const NewAppsecTriggerAdditionalSuspiciousEventsLogging & +NewAppsecLogTrigger::getAppsecTriggerAdditionalSuspiciousEventsLogging() const +{ + return additional_suspicious_events_logging; +} + +const NewAppsecTriggerLogging & +NewAppsecLogTrigger::getAppsecTriggerLogging() const +{ + return appsec_logging; +} + +const NewAppsecTriggerExtendedLogging & +NewAppsecLogTrigger::getAppsecTriggerExtendedLogging() const +{ + return extended_logging; +} + +const NewAppsecTriggerLogDestination & +NewAppsecLogTrigger::getAppsecTriggerLogDestination() const +{ + return log_destination; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_practice.cc b/components/security_apps/local_policy_mgmt_gen/new_practice.cc new file mode 100755 index 0000000..ab2fd01 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_practice.cc @@ -0,0 +1,986 @@ +// 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_practice.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set performance_impacts = {"low", "medium", "high"}; +static const set severity_levels = {"low", "medium", "high", "critical"}; +static const set size_unit = {"bytes", "KB", "MB", "GB"}; +static const set confidences_actions = {"prevent", "detect", "inactive"}; +static const set valid_modes = {"prevent", "detect", "inactive", "prevent-learn", "detect-learn"}; +static const set valid_confidences = {"medium", "high", "critical"}; +static const std::unordered_map key_to_performance_impact_val = { + { "low", "Low or lower"}, + { "medium", "Medium or lower"}, + { "high", "High or lower"} +}; +static const std::unordered_map key_to_severity_level_val = { + { "low", "Low or above"}, + { "medium", "Medium or above"}, + { "high", "High or above"}, + { "critical", "Critical"} +}; +static const std::unordered_map key_to_mode_val = { + { "prevent-learn", "Prevent"}, + { "detect-learn", "Detect"}, + { "prevent", "Prevent"}, + { "detect", "Detect"}, + { "inactive", "Inactive"} +}; +static const std::unordered_map unit_to_int = { + { "bytes", 1}, + { "KB", 1024}, + { "MB", 1048576}, + { "GB", 1073741824} +}; + +void +NewAppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots URI"; + parseAppsecJSONKey("uri", uri, archive_in); +} + +const string & +NewAppSecWebBotsURI::getURI() const +{ + return uri; +} + +std::vector +NewAppSecPracticeAntiBot::getIjectedUris() const +{ + vector injected; + for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + return injected; +} + +std::vector +NewAppSecPracticeAntiBot::getValidatedUris() const +{ + vector validated; + for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); + return validated; +} + +void +NewAppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots"; + parseAppsecJSONKey>("injectedUris", injected_uris, archive_in); + parseAppsecJSONKey>("validatedUris", validated_uris, archive_in); + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << override_mode; + } +} + +void +NewAppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const +{ + vector injected; + vector validated; + for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); + out_ar( + cereal::make_nvp("injected", injected), + cereal::make_nvp("validated", validated) + ); +} + +void +NewAppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Attack Protections"; + parseAppsecJSONKey("csrfEnabled", csrf_protection, archive_in, "inactive"); + parseAppsecJSONKey("errorDisclosureEnabled", error_disclosure, archive_in, "inactive"); + parseAppsecJSONKey("openRedirectEnabled", open_redirect, archive_in, "inactive"); + parseAppsecJSONKey("nonValidHttpMethods", non_valid_http_methods, archive_in, false); +} + +const string +NewAppSecWebAttackProtections::getCsrfProtectionMode() const +{ + if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << csrf_protection + << ". Setting CSRF protection to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(csrf_protection); +} + +const string & +NewAppSecWebAttackProtections::getErrorDisclosureMode() const +{ + return error_disclosure; +} + +bool +NewAppSecWebAttackProtections::getNonValidHttpMethods() const +{ + return non_valid_http_methods; +} + +const string +NewAppSecWebAttackProtections::getOpenRedirectMode() const +{ + if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << open_redirect + << ". Setting Open Redirect mode to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(open_redirect); +} + +void +NewAppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice web attacks spec"; + parseAppsecJSONKey("protections", protections, archive_in); + parseAppsecJSONKey("overrideMode", mode, archive_in, "Unset"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec practice override mode invalid: " << mode; + } + + if (getMode() == "Prevent") { + parseAppsecJSONKey("minimumConfidence", minimum_confidence, archive_in, "critical"); + if (valid_confidences.count(minimum_confidence) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec practice override minimum confidence invalid: " + << minimum_confidence; + } + } else { + minimum_confidence = "Transparent"; + } + parseAppsecJSONKey("maxBodySizeKb", max_body_size_kb, archive_in, 1000000); + parseAppsecJSONKey("maxHeaderSizeBytes", max_header_size_bytes, archive_in, 102400); + parseAppsecJSONKey("maxObjectDepth", max_object_depth, archive_in, 40); + parseAppsecJSONKey("maxUrlSizeBytes", max_url_size_bytes, archive_in, 32768); +} + +int +NewAppSecPracticeWebAttacks::getMaxBodySizeKb() const +{ + return max_body_size_kb; +} + +int +NewAppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const +{ + return max_header_size_bytes; +} + +int +NewAppSecPracticeWebAttacks::getMaxObjectDepth() const +{ + return max_object_depth; +} + +int +NewAppSecPracticeWebAttacks::getMaxUrlSizeBytes() const +{ + return max_url_size_bytes; +} + +const string & +NewAppSecPracticeWebAttacks::getMinimumConfidence() const +{ + return minimum_confidence; +} + +const string & +NewAppSecPracticeWebAttacks::getMode(const string &default_mode) const +{ + if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) { + dbgError(D_LOCAL_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode; + return default_mode; + } + return key_to_practices_val.at(mode); +} + +SnortProtectionsSection::SnortProtectionsSection( + const std::string &_context, + const std::string &_asset_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_source_identifier, + const std::string &_mode, + const std::vector &_files) + : + context(_context), + asset_name(_asset_name), + asset_id(_asset_id), + practice_name(_practice_name), + practice_id(_practice_id), + source_identifier(_source_identifier), + mode(_mode), + files(_files) +{ +} + +void +SnortProtectionsSection::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("files", files), + cereal::make_nvp("assetName", asset_name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("sourceIdentifier", source_identifier) + ); +} + +DetectionRules::DetectionRules( + const std::string &_type, + const std::string &_SSM, + const std::string &_keywords, + const std::vector &_context) + : + type(_type), + SSM(_SSM), + keywords(_keywords), + context(_context) +{ +} + +void +DetectionRules::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Snort protections protections detection rules section"; + parseAppsecJSONKey("type", type, archive_in); + parseAppsecJSONKey("SSM", SSM, archive_in); + parseAppsecJSONKey("keywords", keywords, archive_in); + parseAppsecJSONKey>("context", context, archive_in); + +} + +void +DetectionRules::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("type", type), + cereal::make_nvp("SSM", SSM), + cereal::make_nvp("keywords", keywords), + cereal::make_nvp("context", context) + ); +} + +ProtectionMetadata::ProtectionMetadata( + bool _silent, + const std::string &_protection_name, + const std::string &_severity, + const std::string &_confidence_level, + const std::string &_performance_impact, + const std::string &_last_update, + const std::string &_maintrain_id, + const std::vector &_tags, + const std::vector &_cve_list) + : + silent(_silent), + protection_name(_protection_name), + severity(_severity), + confidence_level(_confidence_level), + performance_impact(_performance_impact), + last_update(_last_update), + maintrain_id(_maintrain_id), + tags(_tags), + cve_list(_cve_list) +{ +} + +void +ProtectionMetadata::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Snort protections protections metadata section"; + parseAppsecJSONKey("silent", silent, archive_in); + parseAppsecJSONKey("protectionName", protection_name, archive_in); + parseAppsecJSONKey("severity", severity, archive_in); + parseAppsecJSONKey("confidenceLevel", confidence_level, archive_in); + parseAppsecJSONKey("performanceImpact", performance_impact, archive_in); + parseAppsecJSONKey("lastUpdate", last_update, archive_in); + parseAppsecJSONKey("maintrainId", maintrain_id, archive_in); + parseAppsecJSONKey>("tags", tags, archive_in); + parseAppsecJSONKey>("cveList", cve_list, archive_in); + +} + +void +ProtectionMetadata::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("protectionName", protection_name), + cereal::make_nvp("severity", severity), + cereal::make_nvp("confidenceLevel", confidence_level), + cereal::make_nvp("performanceImpact", performance_impact), + cereal::make_nvp("lastUpdate", last_update), + cereal::make_nvp("maintrainId", maintrain_id), + cereal::make_nvp("tags", tags), + cereal::make_nvp("cveList", cve_list), + cereal::make_nvp("silent", silent) + ); +} + +ProtectionsProtectionsSection::ProtectionsProtectionsSection( + const ProtectionMetadata &_protection_metadata, + const DetectionRules &_detection_rules) + : + protection_metadata(_protection_metadata), + detection_rules(_detection_rules) +{ +} + +void +ProtectionsProtectionsSection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Snort protections protections section"; + parseAppsecJSONKey("protectionMetadata", protection_metadata, archive_in); + parseAppsecJSONKey("detectionRules", detection_rules, archive_in); +} + +void +ProtectionsProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("protectionMetadata", protection_metadata), + cereal::make_nvp("detectionRules", detection_rules) + ); +} + +ProtectionsSection::ProtectionsSection( + const std::vector &_protections, + const std::string &_name, + const std::string &_modification_time) + : + protections(_protections), + name(_name), + modification_time(_modification_time) +{ +} + +void +ProtectionsSection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Snort protections section"; + parseAppsecJSONKey>("protections", protections, archive_in); +} + +void +ProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("name", name), + cereal::make_nvp("modificationTime", modification_time), + cereal::make_nvp("protections", protections) + ); +} + +const vector & +ProtectionsSection::getProtections() const +{ + return protections; +} + +void +ProtectionsSectionWrapper::serialize(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Snort Section"; + parseAppsecJSONKey("IPSSnortSigs", protections, archive_in); +} + +const vector & +ProtectionsSectionWrapper::getProtections() const +{ + return protections.getProtections(); +} + +void +SnortSection::save(cereal::JSONOutputArchive &out_ar) const +{ + string version = "LocalVersion"; + out_ar( + cereal::make_nvp("VersionId", version), + cereal::make_nvp("SnortProtections", snort_protections), + cereal::make_nvp("protections", protections) + ); +} + +void +SnortSectionWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("IPSSnortSigs", snort) + ); +} + +void +NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "inactive"); + parseAppsecJSONKey>("configmap", config_map, archive_in); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode; + } +} + +void +NewSnortSignaturesAndOpenSchemaAPI::addFile(const string &file_name) +{ + files.push_back(file_name); +} + +const string & +NewSnortSignaturesAndOpenSchemaAPI::getOverrideMode() const +{ + return override_mode; +} + +const vector & +NewSnortSignaturesAndOpenSchemaAPI::getFiles() const +{ + return files; +} + +const vector & +NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const +{ + return config_map; +} + +void +IpsProtectionsRulesSection::save(cereal::JSONOutputArchive &out_ar) const +{ + vector protections; + out_ar( + cereal::make_nvp("action", key_to_mode_val.at(action)), + cereal::make_nvp("confidenceLevel", confidence_level), + cereal::make_nvp("clientProtections", true), + cereal::make_nvp("serverProtections", true), + cereal::make_nvp("protectionTags", protections), + cereal::make_nvp("protectionIds", protections), + cereal::make_nvp("performanceImpact", key_to_performance_impact_val.at(performance_impact)), + cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)), + cereal::make_nvp("protectionsFromYear", protections_from_year) + ); +} + +IpsProtectionsSection::IpsProtectionsSection( + const string &_context, + const string &asset_name, + const string &_asset_id, + const string &_practice_name, + const string &_practice_id, + const string &_source_identifier, + const string &_mode, + const vector &_rules) + : + context(_context), + name(asset_name), + asset_id(_asset_id), + practice_name(_practice_name), + practice_id(_practice_id), + source_identifier(_source_identifier), + mode(_mode), + rules(_rules) +{ +} + +std::string & +IpsProtectionsSection::getMode() +{ + return mode; +} + +void +IpsProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("assetName", name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("defaultAction", key_to_mode_val.at(mode)), + cereal::make_nvp("rules", rules) + ); +} + +void +IPSSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("IpsProtections", ips) + ); +} + +void +IntrusionPreventionWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("IPS", ips) + ); +} + +void +NewIntrusionPrevention::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Intrusion Prevention practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Intrusion Prevention override mode invalid: " << override_mode; + } + parseAppsecJSONKey("maxPerformanceImpact", max_performance_impact, archive_in, "low"); + if (performance_impacts.count(max_performance_impact) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention max performance impact invalid: " + << max_performance_impact; + } + parseAppsecJSONKey("minSeverityLevel", min_severity_level, archive_in, "low"); + if (severity_levels.count(min_severity_level) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention min severity level invalid: " + << min_severity_level; + } + parseAppsecJSONKey("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(high_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention high confidence event invalid: " + << high_confidence_event_action; + } + parseAppsecJSONKey("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(medium_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention medium confidence event invalid: " + << medium_confidence_event_action; + } + parseAppsecJSONKey("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(low_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention low confidence event action invalid: " + << low_confidence_event_action; + } + parseAppsecJSONKey("minCveYear", min_cve_Year, archive_in); +} + +vector +NewIntrusionPrevention::createIpsRules() const +{ + vector ips_rules; + IpsProtectionsRulesSection high_rule( + min_cve_Year, + high_confidence_event_action, + string("High"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(high_rule); + + IpsProtectionsRulesSection med_rule( + min_cve_Year, + medium_confidence_event_action, + string("Medium"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(med_rule); + + IpsProtectionsRulesSection low_rule( + min_cve_Year, + low_confidence_event_action, + string("Low"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(low_rule); + + return ips_rules; +} + +const std::string & +NewIntrusionPrevention::getMode() const +{ + return override_mode; +} + +FileSecurityProtectionsSection::FileSecurityProtectionsSection( + int _file_size_limit, + int _archive_file_size_limit, + bool _allow_files_without_name, + bool _required_file_size_limit, + bool _required_archive_extraction, + const std::string &_context, + const std::string &_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_action, + const std::string &_files_without_name_action, + const std::string &_high_confidence_action, + const std::string &_medium_confidence_action, + const std::string &_low_confidence_action, + const std::string &_severity_level, + const std::string &_file_size_limit_action, + const std::string &_multi_level_archive_action, + const std::string &_unopened_archive_action) + : + file_size_limit(_file_size_limit), + archive_file_size_limit(_archive_file_size_limit), + allow_files_without_name(_allow_files_without_name), + required_file_size_limit(_required_file_size_limit), + required_archive_extraction(_required_archive_extraction), + context(_context), + name(_name), + asset_id(_asset_id), + practice_name(_practice_name), + practice_id(_practice_id), + action(_action), + files_without_name_action(_files_without_name_action), + high_confidence_action(_high_confidence_action), + medium_confidence_action(_medium_confidence_action), + low_confidence_action(_low_confidence_action), + severity_level(_severity_level), + file_size_limit_action(_file_size_limit_action), + multi_level_archive_action(_multi_level_archive_action), + unopened_archive_action(_unopened_archive_action) +{} + +void +FileSecurityProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("assetName", name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("action", key_to_mode_val.at(action)), + cereal::make_nvp("filesWithoutNameAction", key_to_mode_val.at(files_without_name_action)), + cereal::make_nvp("allowFilesWithoutName", allow_files_without_name), + cereal::make_nvp("highConfidence", key_to_mode_val.at(high_confidence_action)), + cereal::make_nvp("mediumConfidence", key_to_mode_val.at(medium_confidence_action)), + cereal::make_nvp("lowConfidence", key_to_mode_val.at(low_confidence_action)), + cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)), + cereal::make_nvp("fileSizeLimitAction", key_to_mode_val.at(file_size_limit_action)), + cereal::make_nvp("fileSizeLimit", file_size_limit), + cereal::make_nvp("requiredFileSizeLimit", required_file_size_limit), + cereal::make_nvp("requiredArchiveExtraction", required_archive_extraction), + cereal::make_nvp("archiveFileSizeLimit", archive_file_size_limit), + cereal::make_nvp("MultiLevelArchiveAction", key_to_mode_val.at(multi_level_archive_action)), + cereal::make_nvp("UnopenedArchiveAction", key_to_mode_val.at(unopened_archive_action)) + ); +} + +void +FileSecuritySection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("FileSecurityProtections", file_security) + ); +} + +void +FileSecurityWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("FileSecurity", file_security) + ); +} + +void +NewFileSecurityArchiveInspection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security Archive Inspection practice"; + parseAppsecJSONKey("extractArchiveFiles", extract_archive_files, archive_in); + parseAppsecJSONKey("scanMaxFileSize", scan_max_file_size, archive_in, 0); + parseAppsecJSONKey("scanMaxFileSizeUnit", scan_max_file_size_unit, archive_in, "bytes"); + if (size_unit.count(scan_max_file_size_unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection scan max file size unit invalid: " + << scan_max_file_size_unit; + } + parseAppsecJSONKey( + "archivedFilesWithinArchivedFiles", + archived_files_within_archived_files, + archive_in, + "inactive"); + if (confidences_actions.count(archived_files_within_archived_files) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived files invalid: " + << archived_files_within_archived_files; + } + parseAppsecJSONKey( + "archivedFilesWhereContentExtractionFailed", + archived_files_where_content_extraction_failed, + archive_in, + "inactive"); + if (confidences_actions.count(archived_files_where_content_extraction_failed) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived file invalid: " + << archived_files_where_content_extraction_failed; + } +} + +int +NewFileSecurityArchiveInspection::getArchiveFileSizeLimit() const +{ + if (unit_to_int.find(scan_max_file_size_unit) == unit_to_int.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << scan_max_file_size_unit + << ". Setting scan max file size unit to 0"; + return 0; + } + return (scan_max_file_size * unit_to_int.at(scan_max_file_size_unit)); +} + +bool +NewFileSecurityArchiveInspection::getrequiredArchiveExtraction() const +{ + return extract_archive_files; +} + +const std::string & +NewFileSecurityArchiveInspection::getMultiLevelArchiveAction() const +{ + return archived_files_within_archived_files; +} + +const std::string & +NewFileSecurityArchiveInspection::getUnopenedArchiveAction() const +{ + return archived_files_where_content_extraction_failed; +} + +void +NewFileSecurityLargeFileInspection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security large File Inspection practice"; + parseAppsecJSONKey("fileSizeLimit", file_size_limit, archive_in); + parseAppsecJSONKey("fileSizeLimitUnit", file_size_limit_unit, archive_in, "bytes"); + if (size_unit.count(file_size_limit_unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security large File Inspection file size limit unit invalid: " + << file_size_limit_unit; + } + parseAppsecJSONKey( + "filesExceedingSizeLimitAction", + files_exceeding_size_limit_action, + archive_in, + "inactive"); + if (confidences_actions.count(files_exceeding_size_limit_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived files invalid: " + << files_exceeding_size_limit_action; + } +} + +int +NewFileSecurityLargeFileInspection::getFileSizeLimit() const +{ + if (unit_to_int.find(file_size_limit_unit) == unit_to_int.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << file_size_limit_unit + << ". Setting file size limit unit to 0"; + return 0; + } + return (file_size_limit * unit_to_int.at(file_size_limit_unit)); +} + +const std::string & +NewFileSecurityLargeFileInspection::getFileSizeLimitAction() const +{ + return files_exceeding_size_limit_action; +} + +void +NewFileSecurity::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec File Security override mode invalid: " << override_mode; + } + parseAppsecJSONKey("minSeverityLevel", min_severity_level, archive_in, "low"); + if (severity_levels.count(min_severity_level) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec File Security min severity level invalid: " << min_severity_level; + } + parseAppsecJSONKey("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(high_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security high confidence event invalid: " + << high_confidence_event_action; + } + parseAppsecJSONKey("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(medium_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security medium confidence event invalid: " + << medium_confidence_event_action; + } + parseAppsecJSONKey("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(low_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security low confidence event action invalid: " + << low_confidence_event_action; + } + parseAppsecJSONKey("unnamedFilesAction", unnamed_files_action, archive_in, "inactive"); + if (confidences_actions.count(unnamed_files_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security low unnamed files action invalid: " + << unnamed_files_action; + } + parseAppsecJSONKey("threatEmulationEnabled", threat_emulation_enabled, archive_in); + parseAppsecJSONKey("archiveInspection", archive_inspection, archive_in); + parseAppsecJSONKey("largeFileInspection", large_file_inspection, archive_in); +} + +const string & +NewFileSecurity::getOverrideMode() const +{ + return override_mode; +} + +const NewFileSecurityArchiveInspection & +NewFileSecurity::getArchiveInspection() const +{ + return archive_inspection; +} + +const NewFileSecurityLargeFileInspection & +NewFileSecurity::getLargeFileInspection() const +{ + return large_file_inspection; +} + +FileSecurityProtectionsSection +NewFileSecurity::createFileSecurityProtectionsSection( + const string &context, + const string &asset_name, + const string &asset_id, + const string &practice_name, + const string &practice_id) const +{ + return FileSecurityProtectionsSection( + getLargeFileInspection().getFileSizeLimit(), + getArchiveInspection().getArchiveFileSizeLimit(), + unnamed_files_action == "prevent" ? true : false, + getLargeFileInspection().getFileSizeLimitAction() == "prevent" ? true : false, + getArchiveInspection().getrequiredArchiveExtraction(), + context, + asset_name, + asset_id, + practice_name, + practice_id, + override_mode, + unnamed_files_action, + high_confidence_event_action, + medium_confidence_event_action, + low_confidence_event_action, + min_severity_level, + getLargeFileInspection().getFileSizeLimitAction(), + getArchiveInspection().getMultiLevelArchiveAction(), + getArchiveInspection().getUnopenedArchiveAction() + ); +} + +void +NewAppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey( + "openapi-schema-validation", + openapi_schema_validation, + archive_in + ); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("fileSecurity", file_security, archive_in); + parseAppsecJSONKey("intrusionPrevention", intrusion_prevention, archive_in); + parseAppsecJSONKey("snortSignatures", snort_signatures, archive_in); + parseAppsecJSONKey("webAttacks", web_attacks, archive_in); + parseAppsecJSONKey("antiBot", anti_bot, archive_in); + parseAppsecJSONKey("name", practice_name, archive_in); +} + +void +NewAppSecPracticeSpec::setName(const string &_name) +{ + practice_name = _name; +} + +const NewSnortSignaturesAndOpenSchemaAPI & +NewAppSecPracticeSpec::getOpenSchemaValidation() const +{ + return openapi_schema_validation; +} + +NewSnortSignaturesAndOpenSchemaAPI & +NewAppSecPracticeSpec::getSnortSignatures() +{ + return snort_signatures; +} + +const NewAppSecPracticeWebAttacks & +NewAppSecPracticeSpec::getWebAttacks() const +{ + return web_attacks; +} + +const NewAppSecPracticeAntiBot & +NewAppSecPracticeSpec::getAntiBot() const +{ + return anti_bot; +} + +const NewIntrusionPrevention & +NewAppSecPracticeSpec::getIntrusionPrevention() const +{ + return intrusion_prevention; +} + +const NewFileSecurity & +NewAppSecPracticeSpec::getFileSecurity() const +{ + return file_security; +} + +const string & +NewAppSecPracticeSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewAppSecPracticeSpec::getName() const +{ + return practice_name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/new_trusted_sources.cc b/components/security_apps/local_policy_mgmt_gen/new_trusted_sources.cc new file mode 100755 index 0000000..ecff3b7 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/new_trusted_sources.cc @@ -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_trusted_sources.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_identifiers = {"headerkey", "JWTKey", "cookie", "sourceip", "x-forwarded-for"}; + +void +NewTrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading trusted sources spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("minNumOfSources", min_num_of_sources, archive_in, 3); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewTrustedSourcesSpec::setName(const string &_name) +{ + name = _name; +} + +int +NewTrustedSourcesSpec::getMinNumOfSources() const +{ + return min_num_of_sources; +} + +const vector & +NewTrustedSourcesSpec::getSourcesIdentifiers() const +{ + return sources_identifiers; +} + +const string & +NewTrustedSourcesSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewTrustedSourcesSpec::getName() const +{ + return name; +} + +void +Identifier::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading source identifiers spec"; + parseAppsecJSONKey("sourceIdentifier", identifier, archive_in); + if (valid_identifiers.count(identifier) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec identifier invalid: " << identifier; + } + parseAppsecJSONKey>("value", value, archive_in); +} + +const string & +Identifier::getIdentifier() const +{ + return identifier; +} + +const vector & +Identifier::getValues() const +{ + return value; +} + +void +NewSourcesIdentifiers::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Sources Identifiers"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewSourcesIdentifiers::setName(const string &_name) +{ + name = _name; +} + +const string & +NewSourcesIdentifiers::getName() const +{ + return name; +} + +const string & +NewSourcesIdentifiers::getAppSecClassName() const +{ + return appsec_class_name; +} + +const vector & +NewSourcesIdentifiers::getSourcesIdentifiers() const +{ + return sources_identifiers; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/policy_maker_utils.cc b/components/security_apps/local_policy_mgmt_gen/policy_maker_utils.cc new file mode 100755 index 0000000..9aea4b7 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/policy_maker_utils.cc @@ -0,0 +1,1590 @@ +// 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 "policy_maker_utils.h" + +using namespace std; + +USE_DEBUG_FLAG(D_NGINX_POLICY); + +void +SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("accessControlV2", rate_limit), + cereal::make_nvp("waap", waap), + cereal::make_nvp("triggers", trrigers), + cereal::make_nvp("rules", rules), + cereal::make_nvp("ips", ips), + cereal::make_nvp("exceptions", exceptions), + cereal::make_nvp("snort", snort), + cereal::make_nvp("fileSecurity", file_security), + cereal::make_nvp("version", policy_version) + ); +} + +void +PolicyWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + security_apps.save(out_ar); +} + +string +PolicyMakerUtils::getPolicyName(const string &policy_path) +{ + string policy_name; + if (policy_path.find_last_of("/") != string::npos) { + policy_name = policy_path.substr(policy_path.find_last_of("/") + 1); + } else { + policy_name = policy_path; + } + if (policy_name.find(".") != string::npos) { + return policy_name.substr(0, policy_name.find(".")); + } + return policy_name; +} + +template +Maybe +PolicyMakerUtils::openFileAsJson(const string &path) +{ + auto maybe_file_as_json = Singleton::Consume::by()->getExecOutput( + getFilesystemPathConfig() + "/bin/yq " + path + " -o json" + ); + + if (!maybe_file_as_json.ok()) { + dbgDebug(D_NGINX_POLICY) << "Could not convert policy from yaml to json"; + return genError("Could not convert policy from yaml to json. Error: " + maybe_file_as_json.getErr()); + } + + auto i_orchestration_tools = Singleton::Consume::by(); + auto maybe_file = i_orchestration_tools->jsonStringToObject( + maybe_file_as_json.unpack() + ); + + if (!maybe_file.ok()) { + string error = "Policy in path: " + path + " was not loaded. Error: " + maybe_file.getErr(); + dbgDebug(D_NGINX_POLICY) << error; + return genError(error); + } + return maybe_file.unpack(); +} + +void +PolicyMakerUtils::clearElementsMaps() +{ + log_triggers.clear(); + web_user_res_triggers.clear(); + inner_exceptions.clear(); + web_apps.clear(); + rules_config.clear(); + ips.clear(); + snort.clear(); + snort_protections.clear(); + file_security.clear(); + rate_limit.clear(); +} + +// LCOV_EXCL_START Reason: no test exist - needed for NGINX config +bool +PolicyMakerUtils::startsWith(const string &str, const string &prefix) +{ + return str.rfind(prefix, 0) == 0; +} + +bool +PolicyMakerUtils::endsWith(const string &str, const string &suffix) +{ + return str.size() >= suffix.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} +// LCOV_EXCL_STOP + +tuple +PolicyMakerUtils::splitHostName(const string &host_name) +{ + string url = host_name; + string uri; + string port; + if (startsWith(url, "http://")) { + url = url.substr(7, url.length() - 1); + port = "80"; + } else if (startsWith(url, "https://")) { + url = url.substr(8, url.length() - 1); + port = "443"; + } + + if (url.find("/") != string::npos) { + uri = url.substr(url.find("/")); + url = url.substr(0, url.find("/")); + } else { + uri = ""; + } + + if (url.find(":") != string::npos) { + port = url.substr(url.find(":") + 1, url.length() - 1); + url = url.substr(0, url.find(":")); + } + + if (host_name == "*") { + url = "Any"; + uri = "Any"; + } + return make_tuple(url, port, uri); +} + +string +PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &policy_path) +{ + clearElementsMaps(); + + stringstream ss; + { + cereal::JSONOutputArchive ar(ss); + policy.save(ar); + } + string policy_str = ss.str(); + try { + ofstream policy_file(policy_path); + policy_file << policy_str; + policy_file.close(); + } catch (const ofstream::failure &e) { + dbgDebug(D_NGINX_POLICY) << "Error while writing new policy to " << policy_path << ", Error: " << e.what(); + return ""; + } + + return policy_str; +} + +template +map +extractAnnotationsNames( + const R &parsed_rule, + const R &default_rule, + const string &policy_name) +{ + map rule_annotation; + string practice_annotation_name; + // TBD: support multiple practices + if (!parsed_rule.getPractices().empty() && !parsed_rule.getPractices()[0].empty()) { + practice_annotation_name = parsed_rule.getPractices()[0]; + } else if (!default_rule.getPractices().empty() && !default_rule.getPractices()[0].empty()) { + practice_annotation_name = default_rule.getPractices()[0]; + } + + if (!practice_annotation_name.empty()) { + rule_annotation[AnnotationTypes::PRACTICE] = policy_name + "/" + practice_annotation_name; + } + + string trigger_annotation_name; + // TBD: support multiple triggers + if (!parsed_rule.getLogTriggers().empty() && !parsed_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = parsed_rule.getLogTriggers()[0]; + } else if (!default_rule.getLogTriggers().empty() && !default_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = default_rule.getLogTriggers()[0]; + } + + if (!trigger_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name; + } + + string exception_annotation_name; + // TBD: support multiple exceptions + if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) { + exception_annotation_name = parsed_rule.getExceptions()[0]; + } else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) { + exception_annotation_name = default_rule.getExceptions()[0]; + } + + if (!exception_annotation_name.empty()) { + rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name; + } + + string web_user_res_annotation_name = + parsed_rule.getCustomResponse().empty() ? + default_rule.getCustomResponse() : + parsed_rule.getCustomResponse(); + + if (!web_user_res_annotation_name.empty()) { + rule_annotation[AnnotationTypes::WEB_USER_RES] = policy_name + "/" + web_user_res_annotation_name; + } + + string source_identifiers_annotation_name = + parsed_rule.getSourceIdentifiers().empty() ? + default_rule.getSourceIdentifiers() : + parsed_rule.getSourceIdentifiers(); + + if (!source_identifiers_annotation_name.empty()) { + rule_annotation[AnnotationTypes::SOURCE_IDENTIFIERS] = policy_name + "/" + source_identifiers_annotation_name; + } + + string trusted_sources_annotation_name = + parsed_rule.getTrustedSources ().empty() ? + default_rule.getTrustedSources() : + parsed_rule.getTrustedSources(); + + if (!trusted_sources_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name; + } + return rule_annotation; +} + +// LCOV_EXCL_START Reason: no test exist +template<> +map +extractAnnotationsNames( + const NewParsedRule &parsed_rule, + const NewParsedRule &default_rule, + const string &policy_name) +{ + map rule_annotation; + string practice_annotation_name; + // TBD: support multiple practices + if (!parsed_rule.getPractices().empty() && !parsed_rule.getPractices()[0].empty()) { + practice_annotation_name = parsed_rule.getPractices()[0]; + } else if (!default_rule.getPractices().empty() && !default_rule.getPractices()[0].empty()) { + practice_annotation_name = default_rule.getPractices()[0]; + } + + if (!practice_annotation_name.empty()) { + rule_annotation[AnnotationTypes::PRACTICE] = policy_name + "/" + practice_annotation_name; + } + + string access_control_practice_name; + // TBD: support multiple practices + if (!parsed_rule.getAccessControlPractices().empty() && !parsed_rule.getAccessControlPractices()[0].empty()) { + access_control_practice_name = parsed_rule.getAccessControlPractices()[0]; + } else if ( !default_rule.getAccessControlPractices().empty() && + !default_rule.getAccessControlPractices()[0].empty()) { + access_control_practice_name = default_rule.getAccessControlPractices()[0]; + } + + if (!access_control_practice_name.empty()) { + rule_annotation[AnnotationTypes::ACCESS_CONTROL_PRACTICE] = policy_name + "/" + access_control_practice_name; + } + + string trigger_annotation_name; + // TBD: support multiple triggers + if (!parsed_rule.getLogTriggers().empty() && !parsed_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = parsed_rule.getLogTriggers()[0]; + } else if (!default_rule.getLogTriggers().empty() && !default_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = default_rule.getLogTriggers()[0]; + } + + if (!trigger_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name; + } + + string exception_annotation_name; + // TBD: support multiple exceptions + if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) { + exception_annotation_name = parsed_rule.getExceptions()[0]; + } else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) { + exception_annotation_name = default_rule.getExceptions()[0]; + } + + if (!exception_annotation_name.empty()) { + rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name; + } + + string web_user_res_annotation_name = + parsed_rule.getCustomResponse().empty() ? + default_rule.getCustomResponse() : + parsed_rule.getCustomResponse(); + + if (!web_user_res_annotation_name.empty()) { + rule_annotation[AnnotationTypes::WEB_USER_RES] = policy_name + "/" + web_user_res_annotation_name; + } + + string source_identifiers_annotation_name = + parsed_rule.getSourceIdentifiers().empty() ? + default_rule.getSourceIdentifiers() : + parsed_rule.getSourceIdentifiers(); + + if (!source_identifiers_annotation_name.empty()) { + rule_annotation[AnnotationTypes::SOURCE_IDENTIFIERS] = policy_name + "/" + source_identifiers_annotation_name; + } + + string trusted_sources_annotation_name = + parsed_rule.getTrustedSources ().empty() ? + default_rule.getTrustedSources() : + parsed_rule.getTrustedSources(); + + if (!trusted_sources_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name; + } + return rule_annotation; +} +// LCOV_EXCL_STOP + +template +container_it +extractElement(container_it begin, container_it end, const string &element_name) +{ + dbgTrace(D_NGINX_POLICY) << "Tryting to find element: " << element_name; + string clean_element_name = element_name.substr(element_name.find("/") + 1); + for (container_it it = begin; it < end; it++) { + if (clean_element_name == it->getName()) { + dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was found"; + return it; + } + } + dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was not found"; + return end; +} + +template +vector +convertMapToVector(map map) +{ + vector vec; + vec.reserve(map.size()); + if (map.empty()) { + return vec; + } + for (const auto &m : map) { + if (!m.first.empty()) vec.push_back(m.second); + } + return vec; +} + +vector +convertExceptionsMapToVector(map> map) +{ + vector vec; + if (map.empty()) { + return vec; + } + for (const auto &m : map) { + if (!m.first.empty()) vec.insert(vec.end(), m.second.begin(), m.second.end()); + } + return vec; +} + +template +R +getAppsecPracticeSpec(const string &practice_annotation_name, const T &policy) +{ + auto practices_vec = policy.getAppSecPracticeSpecs(); + auto practice_it = extractElement(practices_vec.begin(), practices_vec.end(), practice_annotation_name); + + if (practice_it == practices_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec practice"; + return R(); + } + return *practice_it; +} + +// LCOV_EXCL_START Reason: no test exist +AccessControlPracticeSpec +getAccessControlPracticeSpec() +{ + return AccessControlPracticeSpec(); +} + +AccessControlPracticeSpec +getAccessControlPracticeSpec(const string &practice_annotation_name, const V1beta2AppsecLinuxPolicy &policy) +{ + auto practices_vec = policy.getAccessControlPracticeSpecs(); + auto practice_it = extractElement(practices_vec.begin(), practices_vec.end(), practice_annotation_name); + + if (practice_it == practices_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve Access control practice"; + return AccessControlPracticeSpec(); + } + return *practice_it; +} +// LCOV_EXCL_STOP + +template +R +getAppsecTriggerSpec(const string &trigger_annotation_name, const T &policy) +{ + auto triggers_vec = policy.getAppsecTriggerSpecs(); + auto trigger_it = extractElement(triggers_vec.begin(), triggers_vec.end(), trigger_annotation_name); + + if (trigger_it == triggers_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trigger"; + return R(); + } + return *trigger_it; +} + +template +R +getAppsecExceptionSpec(const string &exception_annotation_name, const T &policy) +{ + auto exceptions_vec = policy.getAppsecExceptions(); + auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name); + + if (exception_it == exceptions_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec exception"; + return R(); + } + return *exception_it; +} + +template +R +getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const T &policy) +{ + auto custom_response_vec = policy.getAppSecCustomResponseSpecs(); + auto custom_response_it = extractElement( + custom_response_vec.begin(), + custom_response_vec.end(), + custom_response_annotation_name); + + if (custom_response_it == custom_response_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec custom response"; + return R(); + } + return *custom_response_it; +} + +template +R +getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const T &policy) +{ + auto source_identifiers_vec = policy.getAppsecSourceIdentifierSpecs(); + auto source_identifier_it = extractElement( + source_identifiers_vec.begin(), + source_identifiers_vec.end(), + source_identifiers_annotation_name); + + if (source_identifier_it == source_identifiers_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec source identifier"; + return R(); + } + return *source_identifier_it; +} + +template +R +getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const T &policy) +{ + auto trusted_sources_vec = policy.getAppsecTrustedSourceSpecs(); + auto trusted_sources_it = extractElement( + trusted_sources_vec.begin(), + trusted_sources_vec.end(), + trusted_sources_annotation_name); + + if (trusted_sources_it == trusted_sources_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trusted source"; + return R(); + } + return *trusted_sources_it; +} + +template +LogTriggerSection +extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_spec){ + string verbosity = "Standard"; + string extendLoggingMinSeverity = + trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity(); + bool tpDetect = trigger_spec.getAppsecTriggerLogging().isDetectEvents(); + bool tpPrevent = trigger_spec.getAppsecTriggerLogging().isPreventEvents(); + bool webRequests = trigger_spec.getAppsecTriggerLogging().isAllWebRequests(); + bool webUrlPath = trigger_spec.getAppsecTriggerExtendedLogging().isUrlPath(); + bool webUrlQuery = trigger_spec.getAppsecTriggerExtendedLogging().isUrlQuery(); + bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders(); + bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody(); + bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud(); + bool logToK8sService = trigger_spec.getAppsecTriggerLogDestination().isK8SNeeded(); + bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal(); + bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs(); + bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded(); + bool logToSyslog = trigger_spec.getAppsecTriggerLogDestination().isSyslogNeeded(); + bool responseBody = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isResponseBody(); + bool extendLogging = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isEnabled(); + int cefPortNum = logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerUdpPort() : 0; + string cefIpAddress = + logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerIpv4Address() : ""; + int syslogPortNum = + logToSyslog ? + trigger_spec.getAppsecTriggerLogDestination().getSyslogServerUdpPort() : + 514; + string syslogIpAddress = + logToSyslog ? + trigger_spec.getAppsecTriggerLogDestination().getSyslogServerIpv4Address() : + ""; + + LogTriggerSection log( + trigger_annotation_name, + verbosity, + extendLoggingMinSeverity, + extendLogging, + logToAgent, + logToCef, + logToCloud, + logToK8sService, + logToSyslog, + responseBody, + tpDetect, + tpPrevent, + webBody, + webHeaders, + webRequests, + webUrlPath, + webUrlQuery, + cefPortNum, + cefIpAddress, + syslogPortNum, + syslogIpAddress, + beautify_logs + ); + return log; +} + +// LCOV_EXCL_START Reason: no test exist +template +LogTriggerSection +createLogTriggerSection( + const string &trigger_annotation_name, + const T &policy) +{ + auto trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy); + return extractLogTriggerData(trigger_annotation_name, trigger_spec); +} + +template<> +LogTriggerSection +createLogTriggerSection( + const string &trigger_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + auto trigger_spec = + getAppsecTriggerSpec(trigger_annotation_name, policy); + return extractLogTriggerData(trigger_annotation_name, trigger_spec); +} + +template +WebUserResponseTriggerSection +extractWebUserResponseTriggerSectionrData +( + const string &web_user_res_annotation_name, + const T &web_user_res_spec) +{ + string mode = web_user_res_spec.getMode(); + string response_body = web_user_res_spec.getMessageBody(); + string response_title = web_user_res_spec.getMessageTitle(); + int response_code = web_user_res_spec.getHttpResponseCode(); + + WebUserResponseTriggerSection web_user_res( + web_user_res_annotation_name, + mode, + response_body, + response_code, + response_title + ); + + return web_user_res; +} + +template +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const T &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec(web_user_res_annotation_name, policy); + return extractLogTriggerData(web_user_res_annotation_name, web_user_res_spec); +} + +template<> +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const AppsecLinuxPolicy &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec(web_user_res_annotation_name, policy); + return extractWebUserResponseTriggerSectionrData( + web_user_res_annotation_name, + web_user_res_spec + ); +} + +template<> +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec( + web_user_res_annotation_name, + policy + ); + return extractWebUserResponseTriggerSectionrData( + web_user_res_annotation_name, + web_user_res_spec + ); +} + +vector +addSourceIdentifiersToTrustedSource( + const string &source_identifeir_from_trust, + const vector &values, + const string &source_identifer +) +{ + vector generated_trusted_json; + if (values.empty()) { + generated_trusted_json.push_back( + SourcesIdentifiers(source_identifer, source_identifeir_from_trust) + ); + } else { + for (const string &val : values) { + string src_key = source_identifer + ":" + val; + generated_trusted_json.push_back(SourcesIdentifiers(src_key, source_identifeir_from_trust)); + } + } + + return generated_trusted_json; +} + +template +AppSecTrustedSources +createTrustedSourcesSection( + const string &treusted_sources_annotation_name, + const string &source_identifier_annotation_name, + const T &policy) +{ + TrustedSourcesSpec treusted_sources_spec = + getAppsecTrustedSourceSpecs(treusted_sources_annotation_name, policy); + SourceIdentifierSpecWrapper source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + vector generated_trusted_json; + for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) { + for (const string &source_identifeir_from_trust : treusted_sources_spec.getSourcesIdentifiers()) { + vector tmp_trusted = addSourceIdentifiersToTrustedSource( + source_identifeir_from_trust, + src_ident.getValues(), + src_ident.getSourceIdentifier() + ); + generated_trusted_json.insert(generated_trusted_json.end(), tmp_trusted.begin(), tmp_trusted.end()); + } + } + + AppSecTrustedSources treusted_sources( + treusted_sources_spec.getName(), + treusted_sources_spec.getMinNumOfSources(), + generated_trusted_json + ); + + return treusted_sources; +} + +template<> +AppSecTrustedSources +createTrustedSourcesSection( + const string &treusted_sources_annotation_name, + const string &source_identifier_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + NewTrustedSourcesSpec treusted_sources_spec = + getAppsecTrustedSourceSpecs( + treusted_sources_annotation_name, + policy + ); + NewSourcesIdentifiers source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + vector generated_trusted_json; + for (const Identifier &src_ident : source_identifiers_spec.getSourcesIdentifiers()) { + for (const string &source_identifeir_from_trust : treusted_sources_spec.getSourcesIdentifiers()) { + vector tmp_trusted = addSourceIdentifiersToTrustedSource( + source_identifeir_from_trust, + src_ident.getValues(), + src_ident.getIdentifier() + ); + generated_trusted_json.insert(generated_trusted_json.end(), tmp_trusted.begin(), tmp_trusted.end()); + } + } + + AppSecTrustedSources treusted_sources( + treusted_sources_spec.getName(), + treusted_sources_spec.getMinNumOfSources(), + generated_trusted_json + ); + + return treusted_sources; +} + +template +vector +createExceptionSection( + const string &exception_annotation_name, + const T &policy) +{ + AppsecException exception_spec = + getAppsecExceptionSpec(exception_annotation_name, policy); + vector res; + for (auto exception : exception_spec.getExceptions()) { + ExceptionMatch exception_match(exception); + ExceptionBehavior exception_behavior(exception.getAction()); + res.push_back(InnerException(exception_behavior, exception_match)); + } + return res; +} + +template<> +vector +createExceptionSection( + const string &exception_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + NewAppsecException exception_spec = + getAppsecExceptionSpec(exception_annotation_name, policy); + ExceptionMatch exception_match(exception_spec); + ExceptionBehavior exception_behavior(exception_spec.getAction()); + InnerException inner_exception(exception_behavior, exception_match); + return {inner_exception}; +} + +template +UsersIdentifiersRulebase +createUserIdentifiers( + const string &source_identifier_annotation_name, + const T &policy, + const string &context +) +{ + string jwt_identifier = ""; + vector jwt_identifier_values; + vector user_ident_vec; + SourceIdentifierSpecWrapper source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) { + if (src_ident.getSourceIdentifier() == "JWTKey") { + jwt_identifier = "JWTKey"; + jwt_identifier_values.insert( + jwt_identifier_values.end(), + src_ident.getValues().begin(), + src_ident.getValues().end() + ); + user_ident_vec.push_back(UsersIdentifier("authorization", src_ident.getValues())); + } else { + user_ident_vec.push_back(UsersIdentifier(src_ident.getSourceIdentifier(), src_ident.getValues())); + } + } + UsersIdentifiersRulebase users_ident = UsersIdentifiersRulebase( + context, + jwt_identifier, + jwt_identifier_values, + user_ident_vec + ); + + return users_ident; +} + +template<> +UsersIdentifiersRulebase +createUserIdentifiers( + const string &source_identifier_annotation_name, + const V1beta2AppsecLinuxPolicy &policy, + const string &context +) +{ + string jwt_identifier = ""; + vector jwt_identifier_values; + vector user_ident_vec; + NewSourcesIdentifiers source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + for (const Identifier &src_ident : source_identifiers_spec.getSourcesIdentifiers()) { + if (src_ident.getIdentifier() == "JWTKey") { + jwt_identifier = "JWTKey"; + jwt_identifier_values.insert( + jwt_identifier_values.end(), + src_ident.getValues().begin(), + src_ident.getValues().end() + ); + user_ident_vec.push_back(UsersIdentifier("authorization", src_ident.getValues())); + } else { + user_ident_vec.push_back(UsersIdentifier(src_ident.getIdentifier(), src_ident.getValues())); + } + } + UsersIdentifiersRulebase users_ident = UsersIdentifiersRulebase( + context, + jwt_identifier, + jwt_identifier_values, + user_ident_vec + ); + + return users_ident; +} + +RulesConfigRulebase +createMultiRulesSections( + const string &url, + const string &uri, + const string &practice_id, + const string &practice_name, + const string &practice_type, + const string &log_trigger_name, + const string &log_trigger_id, + const string &log_trigger_type, + const string &web_user_res_vec_name, + const string &web_user_res_vec_id, + const string &web_user_res_vec_type, + const string &asset_name, + const string &exception_name, + const vector &exceptions) +{ + PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name); + vector exceptions_result; + for (auto exception : exceptions) { + exceptions_result.push_back(ParametersSection(exception.getBehaviorId(), exception_name)); + } + + vector triggers; + if (!log_trigger_id.empty()) { + triggers.push_back(RulesTriggerSection(log_trigger_name, log_trigger_id, log_trigger_type)); + } + if (!web_user_res_vec_id.empty()) { + triggers.push_back(RulesTriggerSection( + web_user_res_vec_name, + web_user_res_vec_id, + web_user_res_vec_type) + ); + } + + RulesConfigRulebase rules_config = RulesConfigRulebase( + asset_name, + url, + uri, + {practice}, + exceptions_result, + triggers + ); + + return rules_config; +} + +RulesConfigRulebase +createMultiRulesSections( + const string &url, + const string &uri, + const string &practice_id, + const string &practice_name, + const string &practice_type, + const string &rate_limit_practice_id, + const string &rate_limit_practice_name, + const string &rate_limit_practice_type, + const string &log_trigger_name, + const string &log_trigger_id, + const string &log_trigger_type, + const string &web_user_res_vec_name, + const string &web_user_res_vec_id, + const string &web_user_res_vec_type, + const string &asset_name, + const string &exception_name, + const vector &exceptions) +{ + ParametersSection exception_param = ParametersSection(exceptions[0].getBehaviorId(), exception_name); + + vector practices; + if (!practice_id.empty()) { + practices.push_back(PracticeSection(practice_id, practice_type, practice_name)); + } + if (!rate_limit_practice_id.empty()) { + practices.push_back( + PracticeSection(rate_limit_practice_id, rate_limit_practice_type, rate_limit_practice_name) + ); + } + + vector triggers; + if (!log_trigger_id.empty()) { + triggers.push_back(RulesTriggerSection(log_trigger_name, log_trigger_id, log_trigger_type)); + } + if (!web_user_res_vec_id.empty()) { + triggers.push_back(RulesTriggerSection( + web_user_res_vec_name, + web_user_res_vec_id, + web_user_res_vec_type) + ); + } + + RulesConfigRulebase rules_config = RulesConfigRulebase( + asset_name, + url, + uri, + practices, + {exception_param}, + triggers + ); + + return rules_config; +} + +void +PolicyMakerUtils::createIpsSections( + const string &asset_id, + const string &asset_name, + const string &practice_id, + const string &practice_name, + const string &source_identifier, + const string & context, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + auto apssec_practice = getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy); + + if (apssec_practice.getIntrusionPrevention().getMode().empty()) return; + + IpsProtectionsSection ips_section = IpsProtectionsSection( + context, + asset_name, + asset_id, + practice_name, + practice_id, + source_identifier, + apssec_practice.getIntrusionPrevention().getMode(), + apssec_practice.getIntrusionPrevention().createIpsRules() + ); + + ips[asset_name] = ips_section; +} + +void +PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, const string &practice_name) +{ + auto path = getFilesystemPathConfig() + "/conf/snort/snort_k8s_" + practice_name; + if (snort_protections.find(path) != snort_protections.end()) return; + + auto snort_scriipt_path = getFilesystemPathConfig() + "/scripts/snort_to_ips_local.py"; + auto cmd = "python " + snort_scriipt_path + " " + path + ".rule " + path + ".out " + path + ".err"; + + auto res = Singleton::Consume::by()->getExecOutput(cmd); + + if (!res.ok()) { + dbgWarning(D_LOCAL_POLICY) << res.getErr(); + return; + } + + Maybe maybe_protections = openFileAsJson(path + ".out"); + if (!maybe_protections.ok()){ + dbgWarning(D_LOCAL_POLICY) << maybe_protections.getErr(); + return; + } + + auto i_orchestration_tools = Singleton::Consume::by(); + i_orchestration_tools->removeFile(path + ".rule"); + i_orchestration_tools->removeFile(path + ".out"); + i_orchestration_tools->removeFile(path + ".err"); + + snort_protections[path] = ProtectionsSection( + maybe_protections.unpack().getProtections(), + file_name + ); +} + +void +PolicyMakerUtils::createSnortSections( + const string & context, + const string &asset_name, + const string &asset_id, + const string &practice_name, + const string &practice_id, + const string &source_identifier, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + auto apssec_practice = getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy); + + if (apssec_practice.getSnortSignatures().getOverrideMode() == "inactive" || + apssec_practice.getSnortSignatures().getFiles().size() == 0) { + return; + } + createSnortProtecionsSection(apssec_practice.getSnortSignatures().getFiles()[0], apssec_practice.getName()); + + SnortProtectionsSection snort_section = SnortProtectionsSection( + context, + asset_name, + asset_id, + practice_name, + practice_id, + source_identifier, + apssec_practice.getSnortSignatures().getOverrideMode(), + apssec_practice.getSnortSignatures().getFiles() + ); + + snort[asset_name] = snort_section; +} + +void +PolicyMakerUtils::createFileSecuritySections( + const string &asset_id, + const string &asset_name, + const string &practice_id, + const string &practice_name, + const string &context, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + auto apssec_practice = getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy); + + if (apssec_practice.getFileSecurity().getOverrideMode().empty()) return; + + auto file_security_section = apssec_practice.getFileSecurity().createFileSecurityProtectionsSection( + context, + asset_name, + asset_id, + practice_name, + practice_id + ); + + file_security[asset_name] = file_security_section; +} + +void +PolicyMakerUtils::createRateLimitSection( + const string &asset_name, + const string &url, + const string &uri, + const string &trigger_id, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + if (rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE].empty()) { + return; + } + + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgFlow(D_LOCAL_POLICY) << "Couldn't generate random id for rate limit practice"; + } + auto access_control_practice = getAccessControlPracticeSpec( + rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE], + policy); + + RateLimitRulesTriggerSection trigger; + if (!trigger_id.empty()) { + string trigger_name = rule_annotations[AnnotationTypes::TRIGGER]; + trigger = RateLimitRulesTriggerSection(trigger_id, trigger_name, "Trigger"); + } + + auto rules = access_control_practice.geRateLimit().createRateLimitRulesSection(trigger); + + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]] = RateLimitSection( + asset_name, + url, + uri, + access_control_practice.geRateLimit().getMode(), + practice_id, + rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE], + rules + ); +} + +void +PolicyMakerUtils::createWebAppSection( + const V1beta2AppsecLinuxPolicy &policy, + const RulesConfigRulebase& rule_config, + const string &practice_id, const string &full_url, + const string &default_mode, + map &rule_annotations) +{ + auto apssec_practice = + getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy + ); + PracticeAdvancedConfig practice_advance_config( + apssec_practice.getWebAttacks().getMaxHeaderSizeBytes(), + apssec_practice.getWebAttacks().getMaxBodySizeKb(), + apssec_practice.getWebAttacks().getMaxObjectDepth(), + apssec_practice.getWebAttacks().getMaxUrlSizeBytes() + ); + WebAppSection web_app = WebAppSection( + full_url == "Any" ? "" : full_url, + rule_config.getAssetId(), + rule_config.getAssetName(), + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + rule_config.getContext(), + apssec_practice.getWebAttacks().getMinimumConfidence(), + apssec_practice.getWebAttacks().getMode(default_mode), + practice_advance_config, + apssec_practice.getAntiBot(), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] + ); + web_apps[rule_config.getAssetName()] = web_app; +} + +void +PolicyMakerUtils::createThreatPreventionPracticeSections( + const string &asset_name, + const string &url, + const string &uri, + const string &default_mode, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + if (rule_annotations[AnnotationTypes::PRACTICE].empty()) { + return; + } + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgFlow(D_LOCAL_POLICY) << "Couldn't generate random id for threat prevention practice"; + } + + RulesConfigRulebase rule_config = createMultiRulesSections( + url, + uri, + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "WebApplication", + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]].getId(), + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]].getName(), + "RateLimit", + rule_annotations[AnnotationTypes::TRIGGER], + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(), + "log", + rule_annotations[AnnotationTypes::WEB_USER_RES], + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(), + "WebUserResponse", + asset_name, + rule_annotations[AnnotationTypes::EXCEPTION], + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] + ); + rules_config[rule_config.getAssetName()] = rule_config; + + string current_identifier; + if (!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty()) { + UsersIdentifiersRulebase user_identifiers = createUserIdentifiers( + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy, + rule_config.getContext() + ); + users_identifiers[rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS]] = user_identifiers; + current_identifier = user_identifiers.getIdentifier(); + } + + createIpsSections( + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + current_identifier, + rule_config.getContext(), + policy, + rule_annotations + ); + + createSnortSections( + "practiceId(" + practice_id + ")", + rule_config.getAssetName(), + rule_config.getAssetId(), + rule_annotations[AnnotationTypes::PRACTICE], + practice_id, + current_identifier, + policy, + rule_annotations + ); + + createFileSecuritySections( + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "assetId(" + rule_config.getAssetId() + ")", + policy, + rule_annotations + ); + + if (!web_apps.count(rule_config.getAssetName())) { + createWebAppSection(policy, rule_config, practice_id, asset_name, default_mode, rule_annotations); + } + +} + +SettingsWrapper +createProfilesSection() +{ + 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); +} +// LCOV_EXCL_STOP + +PolicyWrapper +PolicyMakerUtils::combineElementsToPolicy(const string &policy_version) +{ + TriggersWrapper triggers_section( + TriggersRulebase( + convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers) + ) + ); + ExceptionsWrapper exceptions_section({ + ExceptionsRulebase(convertExceptionsMapToVector(inner_exceptions)) + }); + + AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {})); + RulesConfigWrapper rules_config_section(convertMapToVector(rules_config), convertMapToVector(users_identifiers)); + IntrusionPreventionWrapper ips_section(convertMapToVector(ips)); + SnortSectionWrapper snort_section(convertMapToVector(snort), convertMapToVector(snort_protections)); + FileSecurityWrapper file_security_section(convertMapToVector(file_security)); + AccessControlRulebaseWrapper rate_limit_section(convertMapToVector(rate_limit)); + SecurityAppsWrapper security_app_section = SecurityAppsWrapper( + appses_section, + triggers_section, + rules_config_section, + ips_section, + snort_section, + rate_limit_section, + file_security_section, + exceptions_section, + policy_version + ); + + SettingsWrapper profiles_section = createProfilesSection(); + PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section); + + return policy_wrapper; +} + +template +void +PolicyMakerUtils::createPolicyElementsByRule( + const R &rule, + const R &default_rule, + const T &policy, + const string &policy_name) +{ + map rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name); + if ( + !rule_annotations[AnnotationTypes::TRIGGER].empty() && + !log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER]) + ) { + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] = + createLogTriggerSection( + rule_annotations[AnnotationTypes::TRIGGER], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::WEB_USER_RES].empty() && + !web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES]) + ) { + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] = + createWebUserResponseTriggerSection( + rule_annotations[AnnotationTypes::WEB_USER_RES], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::EXCEPTION].empty() && + !inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION]) + ) { + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] = + createExceptionSection( + rule_annotations[AnnotationTypes::EXCEPTION], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::TRUSTED_SOURCES].empty() && + !rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty() && + !trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::PRACTICE].empty() && + !web_apps.count(rule_annotations[AnnotationTypes::PRACTICE]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + if (!rule_annotations[AnnotationTypes::PRACTICE].empty()) { + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + //TBD: return Maybe as part of future error handling + } + + tuple splited_host_name = splitHostName(rule.getHost()); + string full_url = rule.getHost() == "*" + ? "Any" + : rule.getHost(); + + RulesConfigRulebase rule_config = createMultiRulesSections( + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "WebApplication", + rule_annotations[AnnotationTypes::TRIGGER], + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(), + "log", + rule_annotations[AnnotationTypes::WEB_USER_RES], + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(), + "WebUserResponse", + full_url, + rule_annotations[AnnotationTypes::EXCEPTION], + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] + ); + rules_config[rule_config.getAssetName()] = rule_config; + + if (!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty()) { + UsersIdentifiersRulebase user_identifiers = createUserIdentifiers( + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy, + rule_config.getContext() + ); + users_identifiers[rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS]] = user_identifiers; + } + + if (!web_apps.count(rule_config.getAssetName())) { + WebAppSection web_app = WebAppSection( + full_url == "Any" ? "" : full_url, + rule_config.getAssetId(), + rule_config.getAssetName(), + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + rule_config.getContext(), + getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], + rule.getMode(), + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]], + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] + ); + web_apps[rule_config.getAssetName()] = web_app; + } + } +} + +// LCOV_EXCL_START Reason: no test exist +template<> +void +PolicyMakerUtils::createPolicyElementsByRule( + const NewParsedRule &rule, + const NewParsedRule &default_rule, + const V1beta2AppsecLinuxPolicy &policy, + const string &policy_name) +{ + dbgTrace(D_LOCAL_POLICY) << "Creating policy elements from version V1beta2"; + map rule_annotations = + extractAnnotationsNames(rule, default_rule, policy_name); + if ( + !rule_annotations[AnnotationTypes::TRIGGER].empty() && + !log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER]) + ) { + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] = + createLogTriggerSection( + rule_annotations[AnnotationTypes::TRIGGER], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::WEB_USER_RES].empty() && + !web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES]) + ) { + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] = + createWebUserResponseTriggerSection( + rule_annotations[AnnotationTypes::WEB_USER_RES], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::EXCEPTION].empty() && + !inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION]) + ) { + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] = + createExceptionSection( + rule_annotations[AnnotationTypes::EXCEPTION], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::TRUSTED_SOURCES].empty() && + !rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty() && + !trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::PRACTICE].empty() && + !web_apps.count(rule_annotations[AnnotationTypes::PRACTICE]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + string full_url = rule.getHost() == "*" + ? "Any" + : rule.getHost(); + tuple splited_host_name = splitHostName(rule.getHost()); + + createRateLimitSection( + full_url, + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(), + policy, + rule_annotations + ); + + createThreatPreventionPracticeSections( + full_url, + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + rule.getMode(), + policy, + rule_annotations + ); + +} +// LCOV_EXCL_STOP + +template +void +PolicyMakerUtils::createPolicyElements( + const vector &rules, + const R &default_rule, + const T &policy, + const string &policy_name) +{ + for (const R &rule : rules) { + createPolicyElementsByRule(rule, default_rule, policy, policy_name); + } +} + +template +void +PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, const T &appsec_policy) +{ + dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name; + + R default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); + + // add default rule to policy + createPolicyElementsByRule(default_rule, default_rule, appsec_policy, policy_name); + + vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); + createPolicyElements(specific_rules, default_rule, appsec_policy, policy_name); +} + +// LCOV_EXCL_START Reason: no test exist +template<> +void +PolicyMakerUtils::createAgentPolicyFromAppsecPolicy( + const string &policy_name, + const V1beta2AppsecLinuxPolicy &appsec_policy) +{ + dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name; + + NewParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); + + // add default rule to policy + createPolicyElementsByRule( + default_rule, + default_rule, + appsec_policy, + policy_name); + + vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); + createPolicyElements( + specific_rules, + default_rule, + appsec_policy, + policy_name + ); +} +// LCOV_EXCL_STOP + +string +PolicyMakerUtils::proccesSingleAppsecPolicy( + const string &policy_path, + const string &policy_version, + const string &local_appsec_policy_path) +{ + Maybe maybe_policy = openFileAsJson(policy_path); + if (!maybe_policy.ok()){ + dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr(); + return ""; + } + createAgentPolicyFromAppsecPolicy( + getPolicyName(policy_path), + maybe_policy.unpack() + ); + + PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version); + return dumpPolicyToFile( + policy_wrapper, + local_appsec_policy_path + ); +} diff --git a/components/security_apps/local_policy_mgmt_gen/rules_config_section.cc b/components/security_apps/local_policy_mgmt_gen/rules_config_section.cc new file mode 100755 index 0000000..1ffe81d --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/rules_config_section.cc @@ -0,0 +1,369 @@ +// 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 "rules_config_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +AssetUrlParser +AssetUrlParser::parse(const string &uri) +{ + AssetUrlParser result; + + using iterator_t = string::const_iterator; + + if (uri.length() == 0) return result; + + iterator_t uri_end = uri.end(); + + // get query start + iterator_t query_start = find(uri.begin(), uri_end, '?'); + + // protocol + iterator_t protocol_start = uri.begin(); + iterator_t protocol_end = find(protocol_start, uri_end, ':'); //"://"); + + if (protocol_end != uri_end) { + string http_protocol = &*(protocol_end); + if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) { + result.protocol = string(protocol_start, protocol_end); + protocol_end += 3; // :// + } else { + protocol_end = uri.begin(); // no protocol + } + } else { + protocol_end = uri.begin(); // no protocol + } + + // URL + iterator_t host_start = protocol_end; + iterator_t path_start = find(host_start, uri_end, '/'); + + iterator_t host_end = find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':'); + + result.asset_url = string(host_start, host_end); + + // port + if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port + host_end++; + iterator_t portEnd = (path_start != uri_end) ? path_start : query_start; + result.port = string(host_end, portEnd); + } + + // URI + if (path_start != uri_end) result.asset_uri = string(path_start, query_start); + + // query + if (query_start != uri_end) result.query_string = string(query_start, uri.end()); + + return result; +} // Parse + +PracticeSection::PracticeSection( + const string &_id, + const string &_type, + const string &_practice_name +) +{ + auto maybe_type = string_to_practice_type.find(_type); + if (maybe_type == string_to_practice_type.end()) { + dbgError(D_LOCAL_POLICY) << "Illegal pracrtice type: " << _type; + return; + } + + type = _type; + name = _practice_name; + id = _id; +} + +void +PracticeSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("practiceId", id), + cereal::make_nvp("practiceName", name), + cereal::make_nvp("practiceType", type) + ); +} + +// LCOV_EXCL_START Reason: no test exist +ParametersSection::ParametersSection( + const string &_id, + const string &_name) + : + name(_name), + id(_id) +{ + if (_id.empty() && _name.empty()) { + dbgError(D_LOCAL_POLICY) << "Illegal Parameter values. Name and ID are empty"; + return; + } +} + +void +ParametersSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("parameterId", id), + cereal::make_nvp("parameterName", name), + cereal::make_nvp("parameterType", type) + ); +} +// LCOV_EXCL_STOP + +RulesTriggerSection::RulesTriggerSection( + const string &_name, + const string &_id, + const string &_type) + : + name(_name), + id(_id) +{ + if (_name.empty() && _id.empty()) { + dbgError(D_LOCAL_POLICY) << "Illegal values for trigger. Name and ID are empty"; + return; + } + auto maybe_type = string_to_trigger_type.find(_type); + if (maybe_type == string_to_trigger_type.end()) { + dbgError(D_LOCAL_POLICY) << "Illegal trigger type in rule: " << _type; + return; + } + type = _type; +} + +void +RulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("triggerId", id), + cereal::make_nvp("triggerName", name), + cereal::make_nvp("triggerType", type) + ); +} + +RulesConfigRulebase::RulesConfigRulebase( + const string &_name, + const string &_url, + const string &_uri, + vector _practices, + vector _parameters, + vector _triggers) + : + name(_name), + practices(_practices), + parameters(_parameters), + triggers(_triggers) +{ + try { + bool any = _name == "Any" && _url == "Any" && _uri == "Any"; + id = any ? "Any" : _url+_uri; + if (_uri != "/") { + context = any ? "All()" : "Any(" + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(80)" + + string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + + ")," + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(443)" + + string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + + ")" + ")"; + } else { + context = any ? "All()" : "Any(" + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(80)" + ")," + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(443)" + ")" + ")"; + } + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate rule UUID. Error: " << e.what(); + } +} + +void +RulesConfigRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string empty_str = ""; + out_ar( + cereal::make_nvp("assetId", id), + cereal::make_nvp("assetName", name), + cereal::make_nvp("ruleId", id), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("context", context), + cereal::make_nvp("priority", 1), + cereal::make_nvp("isCleanup", false), + cereal::make_nvp("parameters", parameters), + cereal::make_nvp("practices", practices), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("zoneId", empty_str), + cereal::make_nvp("zoneName", empty_str) + ); +} + +const string & +RulesConfigRulebase::getContext() const +{ + return context; +} + +const string & +RulesConfigRulebase::getAssetName() const +{ + return name; +} + +const string & +RulesConfigRulebase::getAssetId() const +{ + return id; +} + +UsersIdentifier::UsersIdentifier(const string &_source_identifier, vector _identifier_values) + : + source_identifier(_source_identifier), + identifier_values(_identifier_values) +{} + +// LCOV_EXCL_START Reason: no test exist +const string & +UsersIdentifier::getIdentifier() const +{ + return source_identifier; +} +// LCOV_EXCL_STOP + +void +UsersIdentifier::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("identifierValues", identifier_values) + ); +} + +UsersIdentifiersRulebase::UsersIdentifiersRulebase( + const string &_context, + const string &_source_identifier, + const vector &_identifier_values, + const vector &_source_identifiers) + : + context(_context), + source_identifier(_source_identifier), + identifier_values(_identifier_values), + source_identifiers(_source_identifiers) +{} + +// LCOV_EXCL_START Reason: no test exist +const string & +UsersIdentifiersRulebase::getIdentifier() const +{ + return source_identifiers[0].getIdentifier(); +} +// LCOV_EXCL_STOP + +void +UsersIdentifiersRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("identifierValues", identifier_values), + cereal::make_nvp("sourceIdentifiers", source_identifiers) + ); +} + +RulesRulebase::RulesRulebase( + const vector &_rules_config, + const vector &_users_identifiers) + : + rules_config(_rules_config), + users_identifiers(_users_identifiers) +{ + sort(rules_config.begin(), rules_config.end(), sortBySpecific); +} + +void +RulesRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulesConfig", rules_config), + cereal::make_nvp("usersIdentifiers", users_identifiers) + ); +} + +bool +RulesRulebase::sortBySpecific( + const RulesConfigRulebase &first, + const RulesConfigRulebase &second +) +{ + return sortBySpecificAux(first.getAssetName(), second.getAssetName()); +} + +bool +RulesRulebase::sortBySpecificAux(const string &first, const string &second) +{ + if (first.empty()) return false; + if (second.empty()) return true; + + AssetUrlParser first_parsed = AssetUrlParser::parse(first); + AssetUrlParser second_parsed = AssetUrlParser::parse(second); + + // sort by URL + if (first_parsed.asset_url == "Any" && second_parsed.asset_url != "Any") return false; + if (second_parsed.asset_url == "Any" && first_parsed.asset_url != "Any") return true; + + // sort by port + if (first_parsed.port == "*" && second_parsed.port != "*") return false; + if (second_parsed.port == "*" && first_parsed.port != "*") return true; + + // sort by URI + if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false; + if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true; + + if (first_parsed.asset_uri.empty()) return false; + if (second_parsed.asset_uri.empty()) return true; + + if (second_parsed.asset_uri.find(first_parsed.asset_uri) != string::npos) return false; + if (first_parsed.asset_uri.find(second_parsed.asset_uri) != string::npos) return true; + + if (first_parsed.asset_url.empty()) return false; + if (second_parsed.asset_url.empty()) return false; + + return second < first; +} + +void +RulesConfigWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", rules_config_rulebase) + ); +} diff --git a/components/security_apps/local_policy_mgmt_gen/settings_section.cc b/components/security_apps/local_policy_mgmt_gen/settings_section.cc new file mode 100755 index 0000000..f066004 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/settings_section.cc @@ -0,0 +1,87 @@ +// 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 "settings_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +AgentSettingsSection::AgentSettingsSection( + const string &_key, + const string &_value) + : + key(_key), + value(_value) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); + } +} + +void +AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("key", key), + cereal::make_nvp("value", value) + ); +} + +const string & +AgentSettingsSection::getSettingId() const +{ + return id; +} + +void +SettingsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string profile_type = "Kubernetes"; + string upgrade_mode = "automatic"; + out_ar( + cereal::make_nvp("agentSettings", agentSettings), + cereal::make_nvp("agentType", profile_type), + cereal::make_nvp("allowOnlyDefinedApplications", false), + cereal::make_nvp("anyFog", true), + cereal::make_nvp("maxNumberOfAgents", 10), + cereal::make_nvp("upgradeMode", upgrade_mode) + ); +} + +SettingsWrapper::SettingsWrapper(SettingsRulebase _agent) : agent(_agent) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what(); + } +} + +void +SettingsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("profileType", profileType), + cereal::make_nvp("tokenType", isToken), + cereal::make_nvp("tokenType", tokenType), + cereal::make_nvp("name", name), + cereal::make_nvp("id", id), + cereal::make_nvp("agent", agent) + ); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/snort_section.cc b/components/security_apps/local_policy_mgmt_gen/snort_section.cc new file mode 100755 index 0000000..c3907aa --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/snort_section.cc @@ -0,0 +1,54 @@ +// 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 "snort_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +AgentSettingsSection::AgentSettingsSection(string _key, string _value) : key(_key), value(_value) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); + } +} + +void +AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("key", key), + cereal::make_nvp("value", value) + ); +} + +void +IpsSnortSigsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string profile_type = "KubernetesProfile"; + string upgrade_mode = "automatic"; + out_ar( + cereal::make_nvp("agentSettings", agentSettings), + cereal::make_nvp("agentType", profile_type), + cereal::make_nvp("allowOnlyDefinedApplications", false), + cereal::make_nvp("anyFog", true), + cereal::make_nvp("maxNumberOfAgents", 10), + cereal::make_nvp("upgradeMode", upgrade_mode) + ); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/local_policy_mgmt_gen/triggers_section.cc b/components/security_apps/local_policy_mgmt_gen/triggers_section.cc new file mode 100755 index 0000000..7c50436 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/triggers_section.cc @@ -0,0 +1,535 @@ +// 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 "triggers_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +static const set valid_modes = {"block-page", "response-code-only"}; +static const set valid_severities = {"high", "critical"}; +static const set valid_protocols = {"tcp", "udp"}; +static const set valid_formats = {"json", "json-formatted"}; + +LogTriggerSection::LogTriggerSection( + const string &_name, + const string &_verbosity, + const string &_extendloggingMinSeverity, + bool _extendlogging, + bool _logToAgent, + bool _logToCef, + bool _logToCloud, + bool _logToK8sService, + bool _logToSyslog, + bool _responseBody, + bool _tpDetect, + bool _tpPrevent, + bool _webBody, + bool _webHeaders, + bool _webRequests, + bool _webUrlPath, + bool _webUrlQuery, + int _cefPortNum, + const string &_cefIpAddress, + int _syslogPortNum, + const string &_syslogIpAddress, + bool _beautify_logs) + : + name(_name), + verbosity(_verbosity), + extendloggingMinSeverity(_extendloggingMinSeverity), + extendlogging(_extendlogging), + logToAgent(_logToAgent), + logToCef(_logToCef), + logToCloud(_logToCloud), + logToK8sService(_logToK8sService), + logToSyslog(_logToSyslog), + responseBody(_responseBody), + tpDetect(_tpDetect), + tpPrevent(_tpPrevent), + webBody(_webBody), + webHeaders(_webHeaders), + webRequests(_webRequests), + webUrlPath(_webUrlPath), + webUrlQuery(_webUrlQuery), + cefPortNum (_cefPortNum), + cefIpAddress (_cefIpAddress), + syslogPortNum (_syslogPortNum), + syslogIpAddress (_syslogIpAddress), + beautify_logs(_beautify_logs) +{ + try { + id = to_string(boost::uuids::random_generator()()); + context = "triggerId(" + id + ")"; + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what(); + } +} + +void +LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + string trigger_type = "log"; + string urlForSyslog = syslogIpAddress + ":" + to_string(syslogPortNum); + string urlForCef = cefIpAddress + ":" + to_string(cefPortNum); + out_ar( + cereal::make_nvp("context", context), + 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("complianceViolations", false), + cereal::make_nvp("complianceWarnings", false), + cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity), + cereal::make_nvp("extendlogging", extendlogging), + cereal::make_nvp("logToAgent", logToAgent), + cereal::make_nvp("logToCef", logToCef), + cereal::make_nvp("logToCloud", logToCloud), + cereal::make_nvp("logToK8sService", logToK8sService), + cereal::make_nvp("logToSyslog", logToSyslog), + cereal::make_nvp("responseBody", responseBody), + cereal::make_nvp("responseCode", false), + cereal::make_nvp("tpDetect", tpDetect), + cereal::make_nvp("tpPrevent", tpPrevent), + cereal::make_nvp("webBody", webBody), + cereal::make_nvp("webHeaders", webHeaders), + cereal::make_nvp("webRequests", webRequests), + cereal::make_nvp("webUrlPath", webUrlPath), + cereal::make_nvp("webUrlQuery", webUrlQuery), + cereal::make_nvp("urlForSyslog", urlForSyslog), + cereal::make_nvp("urlForCef", urlForCef), + cereal::make_nvp("formatLoggingOutput", beautify_logs) + ); +} + +const string & +LogTriggerSection::getTriggerId() const +{ + return id; +} + +const string & +LogTriggerSection::getTriggerName() const +{ + return name; +} + +WebUserResponseTriggerSection::WebUserResponseTriggerSection( + const string &_name, + const string &_details_level, + const string &_response_body, + int _response_code, + const string &_response_title) + : + name(_name), + context(), + details_level(_details_level), + response_body(_response_body), + response_title(_response_title), + response_code(_response_code) +{ + try { + id = to_string(boost::uuids::random_generator()()); + context = "triggerId(" + id + ")"; + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what(); + } +} + +void +WebUserResponseTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("triggerName", name), + cereal::make_nvp("details level", details_level), + cereal::make_nvp("response body", response_body), + cereal::make_nvp("response code", response_code), + cereal::make_nvp("response title", response_title) + ); +} + +const string & +WebUserResponseTriggerSection::getTriggerId() const +{ + return id; +} + +void +AppSecCustomResponseSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec web user response spec"; + parseAppsecJSONKey("http-response-code", httpResponseCode, archive_in, 403); + parseAppsecJSONKey("mode", mode, archive_in, "block-page"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec web user response mode invalid: " << mode; + } + parseAppsecJSONKey("name", name, archive_in); + if (mode == "block-page") { + parseAppsecJSONKey( + "message-body", + messageBody, + archive_in, + "Openappsec's Application Security has detected an attack and blocked it." + ); + parseAppsecJSONKey( + "message-title", + messageTitle, + archive_in, + "Attack blocked by web application protection" + ); + } +} + +void +AppSecCustomResponseSpec::setName(const string &_name) +{ + name = _name; +} + +int +AppSecCustomResponseSpec::getHttpResponseCode() const +{ + return httpResponseCode; +} + +const string & +AppSecCustomResponseSpec::getMessageBody() const +{ + return messageBody; +} + +const string & +AppSecCustomResponseSpec::getMessageTitle() const +{ + return messageTitle; +} + +const string & +AppSecCustomResponseSpec::getMode() const +{ + return mode; +} + +const string & +AppSecCustomResponseSpec::getName() const +{ + return name; +} + +void +TriggersRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("log", logTriggers), + cereal::make_nvp("webUserResponse", webUserResponseTriggers) + ); +} + +void +AppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging"; + parseAppsecJSONKey("allow-events", allow_events, archive_in, false); + parseAppsecJSONKey("drop-events", drop_events, archive_in, false); +} + +void +AppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging"; + parseAppsecJSONKey("enabled", enabled, archive_in, true); + parseAppsecJSONKey("response-body", response_body, archive_in, false); + parseAppsecJSONKey("minimum-severity", minimum_severity, archive_in, "high"); + if (valid_severities.count(minimum_severity) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec AppSec Trigger - Additional Suspicious Events Logging minimum severity invalid: " + << minimum_severity; + } +} + +bool +AppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const +{ + return enabled; +} + +bool +AppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const +{ + return response_body; +} + +const string & +AppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const +{ + return minimum_severity; +} + +void +AppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Logging"; + parseAppsecJSONKey("all-web-requests", all_web_requests, archive_in, false); + parseAppsecJSONKey("detect-events", detect_events, archive_in, false); + parseAppsecJSONKey("prevent-events", prevent_events, archive_in, true); +} + +bool +AppsecTriggerLogging::isAllWebRequests() const +{ + return all_web_requests; +} + +bool +AppsecTriggerLogging::isDetectEvents() const +{ + return detect_events; +} + +bool +AppsecTriggerLogging::isPreventEvents() const +{ + return prevent_events; +} + +void +AppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Extended Logging"; + parseAppsecJSONKey("http-headers", http_headers, archive_in, false); + parseAppsecJSONKey("request-body", request_body, archive_in, false); + parseAppsecJSONKey("url-path", url_path, archive_in, false); + parseAppsecJSONKey("url-query", url_query, archive_in, false); +} + +bool +AppsecTriggerExtendedLogging::isHttpHeaders() const +{ + return http_headers; +} + +bool +AppsecTriggerExtendedLogging::isRequestBody() const +{ + return request_body; +} + +bool +AppsecTriggerExtendedLogging::isUrlPath() const +{ + return url_path; +} + +bool +AppsecTriggerExtendedLogging::isUrlQuery() const +{ + return url_query; +} + +void +LoggingService::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("address", address, archive_in); + parseAppsecJSONKey("proto", proto, archive_in); + if (valid_protocols.count(proto) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto; + } + + parseAppsecJSONKey("port", port, archive_in, 514); +} + +const string & +LoggingService::getAddress() const +{ + return address; +} + +int +LoggingService::getPort() const +{ + return port; +} + + +void +StdoutLogging::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("format", format, archive_in, "json"); + if (valid_formats.count(format) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Stdout Logging - format invalid: " << format; + } +} + +const string & +StdoutLogging::getFormat() const +{ + return format; +} + +void +AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination"; + // TBD: support "file" + parseAppsecJSONKey("cloud", cloud, archive_in, false); + auto mode = Singleton::Consume::by()->getOrchestrationMode(); + auto env_type = Singleton::Consume::by()->getEnvType(); + bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S); + parseAppsecJSONKey("k8s-service", k8s_service, archive_in, k8s_service_default); + + StdoutLogging stdout_log; + parseAppsecJSONKey("stdout", stdout_log, archive_in); + agent_local = !(stdout_log.getFormat().empty()); + beautify_logs = stdout_log.getFormat() == "json-formatted"; + parseAppsecJSONKey("syslog-service", syslog_service, archive_in); + parseAppsecJSONKey("cef-service", cef_service, archive_in); +} + +int +AppsecTriggerLogDestination::getCefServerUdpPort() const +{ + return getCefServiceData().getPort(); +} + +int +AppsecTriggerLogDestination::getSyslogServerUdpPort() const +{ + return getSyslogServiceData().getPort(); +} + +bool +AppsecTriggerLogDestination::isAgentLocal() const +{ + return agent_local; +} + +bool +AppsecTriggerLogDestination::shouldBeautifyLogs() const +{ + return beautify_logs; +} + +bool +AppsecTriggerLogDestination::getCloud() const +{ + return cloud; +} + +bool +AppsecTriggerLogDestination::isK8SNeeded() const +{ + return k8s_service; +} + +bool +AppsecTriggerLogDestination::isCefNeeded() const +{ + return !getCefServiceData().getAddress().empty(); +} + +bool +AppsecTriggerLogDestination::isSyslogNeeded() const +{ + return !getSyslogServiceData().getAddress().empty(); +} + +const +string & AppsecTriggerLogDestination::getSyslogServerIpv4Address() const +{ + return getSyslogServiceData().getAddress(); +} + +const string & +AppsecTriggerLogDestination::getCefServerIpv4Address() const +{ + return getCefServiceData().getAddress(); +} + +const LoggingService & +AppsecTriggerLogDestination::getSyslogServiceData() const +{ + return syslog_service; +} + +const LoggingService & +AppsecTriggerLogDestination::getCefServiceData() const +{ + return cef_service; +} + +void +AppsecTriggerSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec trigger spec"; + parseAppsecJSONKey( + "access-control-logging", + access_control_logging, + archive_in + ); + parseAppsecJSONKey( + "additional-suspicious-events-logging", + additional_suspicious_events_logging, + archive_in + ); + parseAppsecJSONKey("appsec-logging", appsec_logging, archive_in); + parseAppsecJSONKey("extended-logging", extended_logging, archive_in); + parseAppsecJSONKey("log-destination", log_destination, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +AppsecTriggerSpec::setName(const string &_name) +{ + name = _name; +} + +const string & +AppsecTriggerSpec::getName() const +{ + return name; +} + +const AppsecTriggerAdditionalSuspiciousEventsLogging & +AppsecTriggerSpec::getAppsecTriggerAdditionalSuspiciousEventsLogging() const +{ + return additional_suspicious_events_logging; +} + +const AppsecTriggerLogging & +AppsecTriggerSpec::getAppsecTriggerLogging() const +{ + return appsec_logging; +} + +const AppsecTriggerExtendedLogging & +AppsecTriggerSpec::getAppsecTriggerExtendedLogging() const +{ + return extended_logging; +} + +const AppsecTriggerLogDestination & +AppsecTriggerSpec::getAppsecTriggerLogDestination() const +{ + return log_destination; +} + +void +TriggersWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", triggers_rulebase) + ); +} diff --git a/components/security_apps/local_policy_mgmt_gen/trusted_sources_section.cc b/components/security_apps/local_policy_mgmt_gen/trusted_sources_section.cc new file mode 100755 index 0000000..f8053a4 --- /dev/null +++ b/components/security_apps/local_policy_mgmt_gen/trusted_sources_section.cc @@ -0,0 +1,152 @@ +// 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 "policy_maker_utils.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +static const set valid_source_identifiers = {"headerkey", "JWTKey", "cookie", "sourceip", "x-forwarded-for"}; + +void +TrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading trusted sources spec"; + parseAppsecJSONKey("minNumOfSources", min_num_of_sources, archive_in, 3); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +TrustedSourcesSpec::setName(const string &_name) +{ + name = _name; +} + +int +TrustedSourcesSpec::getMinNumOfSources() const +{ + return min_num_of_sources; +} + +const vector & +TrustedSourcesSpec::getSourcesIdentifiers() const +{ + return sources_identifiers; +} + +const string & +TrustedSourcesSpec::getName() const +{ + return name; +} + +void +SourcesIdentifiers::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("value", value) + ); +} + +const string & +SourcesIdentifiers::getSourceIdent() const +{ + return source_identifier; +} + +void +SourceIdentifierSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading source identifiers spec"; + parseAppsecJSONKey("sourceIdentifier", source_identifier, archive_in); + if (valid_source_identifiers.count(source_identifier) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec source identifier invalid: " << source_identifier; + } + parseAppsecJSONKey>("value", value, archive_in); +} + +const string & +SourceIdentifierSpec::getSourceIdentifier() const +{ + return source_identifier; +} + +const vector & +SourceIdentifierSpec::getValues() const +{ + return value; +} + +void +SourceIdentifierSpecWrapper::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Source Identifier Spec Wrapper"; + parseAppsecJSONKey>("identifiers", identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +SourceIdentifierSpecWrapper::setName(const string &_name) +{ + name = _name; +} + +const string & +SourceIdentifierSpecWrapper::getName() const +{ + return name; +} + +const vector & +SourceIdentifierSpecWrapper::getIdentifiers() const +{ + return identifiers; +} + +AppSecTrustedSources::AppSecTrustedSources( + const string &_name, + int _num_of_sources, + const vector &_sources_identifiers) + : + name(_name), + num_of_sources(_num_of_sources), + sources_identifiers(_sources_identifiers) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what(); + } +} + +void +AppSecTrustedSources::save(cereal::JSONOutputArchive &out_ar) const +{ + string parameter_type = "TrustedSource"; + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("numOfSources", num_of_sources), + cereal::make_nvp("sourcesIdentifiers", sources_identifiers), + cereal::make_nvp("parameterType", parameter_type) + ); +} + +const vector & +AppSecTrustedSources::getSourcesIdentifiers() const +{ + return sources_identifiers; +} diff --git a/components/security_apps/orchestration/CMakeLists.txt b/components/security_apps/orchestration/CMakeLists.txt index fc76575..4c500e8 100755 --- a/components/security_apps/orchestration/CMakeLists.txt +++ b/components/security_apps/orchestration/CMakeLists.txt @@ -12,7 +12,6 @@ add_subdirectory(manifest_controller) add_subdirectory(update_communication) add_subdirectory(details_resolver) add_subdirectory(health_check) -add_subdirectory(local_policy_mgmt_gen) add_subdirectory(env_details) #add_subdirectory(orchestration_ut) diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h index 97958c1..5a36ff8 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h @@ -42,6 +42,16 @@ checkSamlPortal(const string &command_output) return genError("Current host does not have SAML Portal configured"); } +Maybe +getIDAGaia(const string &command_output) +{ + if (command_output.find("Portal is running") != string::npos) { + return string("ida_gaia"); + } + + return genError("Current host does not have SAML Portal configured"); +} + Maybe checkIDP(shared_ptr file_stream) { @@ -226,58 +236,24 @@ getSmbGWIPSecVPNBlade(const string &command_output) { return getSmbBlade(command_output, "IPSec VPN Blade was not found"); } - -Maybe -getMgmtParentObjAttr(shared_ptr file_stream, const string &parent_obj, const string &attr) -{ - string line; - bool found_parent_obj = false; - while (getline(*file_stream, line)) { - size_t parent_obj_pos = line.find(parent_obj); - if (parent_obj_pos != string::npos) found_parent_obj = true; - if (!found_parent_obj) continue; - - size_t attr_pos = line.find(attr); - if (attr_pos == string::npos) continue; - line = line.substr(attr_pos + attr.size()); - return line; - } - return genError("Parent object attribute was not found. Attr: " + attr); -} #endif // gaia || smb #if defined(gaia) Maybe -getMgmtParentObjUid(shared_ptr file_stream) +getMgmtParentObjUid(const string &command_output) { - auto maybe_unparsed_uid = getMgmtParentObjAttr(file_stream, "cluster_object", "Uid "); - if (!maybe_unparsed_uid.ok()) { - return maybe_unparsed_uid; - } - const string &unparsed_uid = maybe_unparsed_uid.unpack(); - auto maybe_uid = chopHeadAndTail(unparsed_uid, "(\"{", "}\")"); - if (!maybe_uid.ok()) { - return maybe_uid; - } - string uid = maybe_uid.unpack(); - transform(uid.begin(), uid.end(), uid.begin(), ::tolower); - return uid; + return getAttr(command_output, "Parent object uuid was not found"); } Maybe -getMgmtParentObjName(shared_ptr file_stream) +getMgmtParentObjName(const string &command_output) { - auto maybe_unparsed_name = getMgmtParentObjAttr(file_stream, "cluster_object", "Name "); - if (!maybe_unparsed_name.ok()) { - return maybe_unparsed_name; - } - const string &unparsed_name = maybe_unparsed_name.unpack(); - return chopHeadAndTail(unparsed_name, "(", ")"); + return getAttr(command_output, "Parent object name was not found"); } #elif defined(smb) Maybe -getMgmtParentObjUid(const string &command_output) +getSmbMgmtParentObjUid(const string &command_output) { if (!command_output.empty()) { return command_output; @@ -286,7 +262,7 @@ getMgmtParentObjUid(const string &command_output) } Maybe -getMgmtParentObjName(const string &command_output) +getSmbMgmtParentObjName(const string &command_output) { if (!command_output.empty()) { return command_output; @@ -314,6 +290,34 @@ getOsRelease(shared_ptr file_stream) return genError("Os release was not found"); } +Maybe +getWaapModelVersion(shared_ptr file_stream) +{ + string line; + static const int max_lines = 5; + int i = 0; + bool found_key = false; + while (i < max_lines && getline(*file_stream, line)) { + if (!found_key) { + size_t index = line.find("\"model_version\":"); + if (index != string::npos) { + found_key = true; + } + } else { + size_t start = line.find_first_of('"'); + size_t end = line.find_last_of('"'); + if (start != string::npos && end != string::npos && end > start) { + return line.substr(start + 1, end - start - 1); + } else { + return genError("Model version value unreadable"); + } + } + i++; + } + + return genError("Model version was not found"); +} + #if defined(alpine) string & ltrim(string &s) diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h index e979501..7beed3d 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h @@ -55,6 +55,19 @@ SHELL_CMD_HANDLER( #if defined(gaia) SHELL_CMD_HANDLER("hasSupportedBlade", "enabled_blades", checkHasSupportedBlade) SHELL_CMD_HANDLER("hasSamlPortal", "mpclient status saml-vpn", checkSamlPortal) +SHELL_CMD_HANDLER("requiredNanoServices", "mpclient status saml-vpn", getIDAGaia) +SHELL_CMD_HANDLER( + "cpProductIntegrationMgmtParentObjectName", + "cat $FWDIR/database/myself_objects.C " + "| awk -F '[:()]' '/:cluster_object/ {found=1; next} found && /:Name/ {print $3; exit}'", + getMgmtParentObjName +) +SHELL_CMD_HANDLER( + "cpProductIntegrationMgmtParentObjectUid", + "cat $FWDIR/database/myself_objects.C " + "| awk -F'[{}]' '/:cluster_object/ { found=1; next } found && /:Uid/ { uid=tolower($2); print uid; exit }'", + getMgmtParentObjUid +) SHELL_CMD_HANDLER( "Hardware", "cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1", @@ -81,12 +94,12 @@ SHELL_CMD_HANDLER( SHELL_CMD_HANDLER( "cpProductIntegrationMgmtParentObjectName", "cpsdwan get_data | jq -r .cluster_name", - getMgmtParentObjName + getSmbMgmtParentObjName ) SHELL_CMD_HANDLER( "cpProductIntegrationMgmtParentObjectUid", "cpsdwan get_data | jq -r .cluster_uuid", - getMgmtParentObjUid + getSmbMgmtParentObjUid ) SHELL_CMD_HANDLER( "cpProductIntegrationMgmtObjectName", @@ -143,4 +156,6 @@ FILE_CONTENT_HANDLER( FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease) #endif // gaia || smb +FILE_CONTENT_HANDLER("AppSecModelVersion", "/etc/cp/conf/waap/waap.data", getWaapModelVersion) + #endif // FILE_CONTENT_HANDLER diff --git a/components/security_apps/orchestration/details_resolver/details_resolving_handler.cc b/components/security_apps/orchestration/details_resolver/details_resolving_handler.cc index b8e0cbf..33046cc 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolving_handler.cc +++ b/components/security_apps/orchestration/details_resolver/details_resolving_handler.cc @@ -22,6 +22,7 @@ #include "maybe_res.h" #include "enum_array.h" #include "i_shell_cmd.h" +#include "i_orchestration_tools.h" #include "config.h" using namespace std; @@ -77,7 +78,8 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const const string &path = file_handler.second.first; FileContentHandler handler = file_handler.second.second; - shared_ptr in_file = make_shared(path); + shared_ptr in_file = + Singleton::Consume::by()->fileStreamWrapper(path); if (!in_file->is_open()) { dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path; continue; diff --git a/components/security_apps/orchestration/details_resolver/details_resolving_handler.h b/components/security_apps/orchestration/details_resolver/details_resolving_handler.h index 7ffe122..0e70bce 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolving_handler.h +++ b/components/security_apps/orchestration/details_resolver/details_resolving_handler.h @@ -18,11 +18,13 @@ #include #include "i_shell_cmd.h" +#include "i_orchestration_tools.h" #include "i_agent_details_reporter.h" class DetailsResolvingHanlder : Singleton::Consume, + Singleton::Consume, Singleton::Consume { public: diff --git a/components/security_apps/orchestration/downloader/curl_client.cc b/components/security_apps/orchestration/downloader/curl_client.cc index 2c9fb41..dce531a 100755 --- a/components/security_apps/orchestration/downloader/curl_client.cc +++ b/components/security_apps/orchestration/downloader/curl_client.cc @@ -278,6 +278,36 @@ HttpsCurl::HttpsCurl(const HttpsCurl &other) : HttpCurl(other), ca_path(other.ca_path) {} +bool +HttpsCurl::downloadOpenAppsecPackages() +{ + char errorstr[CURL_ERROR_SIZE]; + CURL* curl_handle = curl_easy_init(); + if (!curl_handle) return false; + + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + + curl_easy_setopt(curl_handle, CURLOPT_URL, ("https://" + curl_url).c_str()); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeResponseCallback); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &out_file); + + curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorstr); + + CURLcode res = curl_easy_perform(curl_handle); + if (res == CURLE_OK) { + dbgTrace(D_HTTP_REQUEST) << "CURL HTTP request successfully completed."; + } else { + dbgWarning(D_HTTP_REQUEST) << "CURL result " + string(curl_easy_strerror(res)); + curl_easy_cleanup(curl_handle); + return false; + } + + curl_easy_cleanup(curl_handle); + return true; +} + void HttpsCurl::setCurlOpts(long timeout, HTTP_VERSION http_version) { @@ -299,9 +329,9 @@ HttpsCurl::setCurlOpts(long timeout, HTTP_VERSION http_version) curl_easy_setopt(curl_handle, CURLOPT_HTTP_VERSION, http_version); //SSL options - if (getProfileAgentSettingWithDefault( - false, - "agent.config.message.ignoreSslValidation") == false) + if ( + getProfileAgentSettingWithDefault(false, "agent.config.message.ignoreSslValidation") == false + ) { curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_verify_certificate); diff --git a/components/security_apps/orchestration/downloader/curl_client.h b/components/security_apps/orchestration/downloader/curl_client.h index 9104f29..fd99dd8 100755 --- a/components/security_apps/orchestration/downloader/curl_client.h +++ b/components/security_apps/orchestration/downloader/curl_client.h @@ -105,6 +105,7 @@ public: static CURLcode ssl_ctx_verify_certificate(CURL *curl, void *ssl_ctx, void *opq); static int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx); void setCurlOpts(long timeout = 60L, HTTP_VERSION http_version = HTTP_VERSION::HTTP_VERSION_1_1) override; + bool downloadOpenAppsecPackages(); private: std::string ca_path; diff --git a/components/security_apps/orchestration/downloader/downloader_ut/downloader_ut.cc b/components/security_apps/orchestration/downloader/downloader_ut/downloader_ut.cc index 14c6721..df7fa0b 100755 --- a/components/security_apps/orchestration/downloader/downloader_ut/downloader_ut.cc +++ b/components/security_apps/orchestration/downloader/downloader_ut/downloader_ut.cc @@ -51,7 +51,7 @@ TEST_F(DownloaderTest, downloadFileFromFog) calculateChecksum(Package::ChecksumTypes::SHA256, "/tmp/virtualSettings.download") ).WillOnce(Return(string("123"))); - EXPECT_CALL(mock_orchestration_tools, writeFile(fog_response, "/tmp/virtualSettings.download")) + EXPECT_CALL(mock_orchestration_tools, writeFile(fog_response, "/tmp/virtualSettings.download", false)) .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, isNonEmptyFile("/tmp/virtualSettings.download")).WillOnce(Return(true)); @@ -183,7 +183,7 @@ TEST_F(DownloaderTest, downloadEmptyFileFromFog) EXPECT_CALL(mock_communication, downloadAttributeFile(resourse_file)).WillOnce(Return(fog_response)); - EXPECT_CALL(mock_orchestration_tools, writeFile(fog_response, "/tmp/manifest.download")) + EXPECT_CALL(mock_orchestration_tools, writeFile(fog_response, "/tmp/manifest.download", false)) .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, isNonEmptyFile("/tmp/manifest.download")).WillOnce(Return(false)); @@ -342,13 +342,23 @@ TEST_F(DownloaderTest, download_virtual_policy) EXPECT_CALL(mock_communication, downloadAttributeFile(resourse_file)).WillOnce(Return(fog_response)); - EXPECT_CALL(mock_orchestration_tools, writeFile(tenant_0000_file, "/tmp/virtualPolicy_0000_profile_1234.download")) - .WillOnce(Return(true)); + EXPECT_CALL( + mock_orchestration_tools, + writeFile( + tenant_0000_file, + "/tmp/virtualPolicy_0000_profile_1234.download", + false) + ).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, fillKeyInJson(_, _, _)).WillRepeatedly(Return()); - EXPECT_CALL(mock_orchestration_tools, writeFile(tenant_1111_file, "/tmp/virtualPolicy_1111_profile_1235.download")) - .WillOnce(Return(true)); + EXPECT_CALL( + mock_orchestration_tools, + writeFile( + tenant_1111_file, + "/tmp/virtualPolicy_1111_profile_1235.download", + false) + ).WillOnce(Return(true)); map, string> expected_downloaded_files = { @@ -427,7 +437,8 @@ TEST_F(DownloaderTest, download_virtual_settings) mock_orchestration_tools, writeFile( tenant_0000_file, - tenant_0000_path.str() + tenant_0000_path.str(), + false ) ).WillOnce(Return(true)); diff --git a/components/security_apps/orchestration/downloader/http_client.h b/components/security_apps/orchestration/downloader/http_client.h index ae725f9..68a4bb0 100755 --- a/components/security_apps/orchestration/downloader/http_client.h +++ b/components/security_apps/orchestration/downloader/http_client.h @@ -37,8 +37,8 @@ private: std::string loadCAChainDir(); Maybe getFileSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token); Maybe getFileHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token); - Maybe curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token); Maybe curlGetFileOverHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token); + Maybe curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token); }; // LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/downloader/https_client.cc b/components/security_apps/orchestration/downloader/https_client.cc index 33d9031..8ef61a3 100755 --- a/components/security_apps/orchestration/downloader/https_client.cc +++ b/components/security_apps/orchestration/downloader/https_client.cc @@ -592,8 +592,13 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s proxy_config->getProxyCredentials(ProxyProtocol::HTTPS), cert_file_path); - ssl_curl_client.setCurlOpts(); - bool connection_ok = ssl_curl_client.connect(); + bool connection_ok; + if (url.getBaseURL().unpack() == "downloads.openappsec.io") { + connection_ok = ssl_curl_client.downloadOpenAppsecPackages(); + } else { + ssl_curl_client.setCurlOpts(); + connection_ok = ssl_curl_client.connect(); + } if (!connection_ok) { stringstream url_s; diff --git a/components/security_apps/orchestration/health_check/health_check.cc b/components/security_apps/orchestration/health_check/health_check.cc index 96a43f0..db81a41 100755 --- a/components/security_apps/orchestration/health_check/health_check.cc +++ b/components/security_apps/orchestration/health_check/health_check.cc @@ -21,6 +21,7 @@ #include "config.h" #include "log_generator.h" #include "health_check_manager.h" +#include "agent_core_utilities.h" using namespace std; using namespace ReportIS; @@ -145,9 +146,11 @@ private: initCloudVendorConfig() { static const map> ip_port_defaults_map = { - {"Azure", make_pair("168.63.129.16", 8117)}, - {"Aws", make_pair("", 8117)} + {"Azure", make_pair(getenv("DOCKER_RPM_ENABLED") ? "" : "168.63.129.16", 8117)}, + {"Aws", make_pair("", 8117)}, + {"Local", make_pair("", 8117)} }; + auto cloud_vendor_maybe = getSetting("reverseProxy", "cloudVendorName"); if (cloud_vendor_maybe.ok()) { const string cloud_vendor = cloud_vendor_maybe.unpack(); @@ -247,13 +250,36 @@ private: ); } + HealthCheckStatus + getStandaloneHealthStatus() + { + if (!getenv("DOCKER_RPM_ENABLED")) return HealthCheckStatus::IGNORED; + + static const string standalone_cmd = "/usr/sbin/cpnano -s --docker-rpm; echo $?"; + dbgTrace(D_HEALTH_CHECK) << "Checking the standalone docker health status with command: " << standalone_cmd; + + auto maybe_result = Singleton::Consume::by()->getExecOutput(standalone_cmd, 1000); + if (!maybe_result.ok()) { + dbgWarning(D_HEALTH_CHECK) << "Unable to get the standalone docker status. Returning unhealthy status."; + return HealthCheckStatus::UNHEALTHY; + } + dbgTrace(D_HEALTH_CHECK) << "Got response: " << maybe_result.unpack(); + + auto response = NGEN::Strings::removeTrailingWhitespaces(maybe_result.unpack()); + + if (response.back() == '0') return HealthCheckStatus::HEALTHY; + if (response.back() == '1') return HealthCheckStatus::UNHEALTHY; + + return HealthCheckStatus::DEGRADED; + } + bool nginxContainerIsRunning() { static const string nginx_container_name = "cp_nginx_gaia"; static const string cmd_running = "docker ps --filter name=" + nginx_container_name + " --filter status=running"; - dbgTrace(D_HEALTH_CHECK) << "Checking if the container is running with the commmand: " << cmd_running; + dbgTrace(D_HEALTH_CHECK) << "Checking if the container is running with the command: " << cmd_running; auto maybe_result = Singleton::Consume::by()->getExecOutput(cmd_running); if (!maybe_result.ok()) { @@ -263,7 +289,6 @@ private: } return (*maybe_result).find(nginx_container_name) != string::npos; - } void @@ -279,7 +304,7 @@ private: { if (open_connections_counter >= max_connections) { dbgDebug(D_HEALTH_CHECK) - << "Cannot serve new client, reached maximun open connections bound which is:" + << "Cannot serve new client, reached maximum open connections bound which is:" << open_connections_counter << "maximum allowed: " << max_connections; @@ -331,6 +356,42 @@ private: "health check failed\r\n"; static const vector failure_response_buffer(failure_response.begin(), failure_response.end()); + static const string degraded_response = + "HTTP/1.1 202 OK\r\n" + "Content-Length: 22\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "health check partial\r\n"; + static const vector degraded_response_buffer(degraded_response.begin(), degraded_response.end()); + + HealthCheckStatus standalone_status = getStandaloneHealthStatus(); + if (standalone_status != HealthCheckStatus::IGNORED) { + if (standalone_status == HealthCheckStatus::HEALTHY) { + dbgDebug(D_HEALTH_CHECK) + << "Standalone status is healthy, returning the following response: " + << success_response; + i_socket->writeData(curr_client_socket, success_response_buffer); + closeCurrentSocket(curr_client_socket, curr_routine_id); + return; + } + + if (standalone_status == HealthCheckStatus::UNHEALTHY) { + dbgDebug(D_HEALTH_CHECK) + << "Standalone status in unhealthy, returning the following response: " + << failure_response; + i_socket->writeData(curr_client_socket, failure_response_buffer); + closeCurrentSocket(curr_client_socket, curr_routine_id); + return; + } + + dbgDebug(D_HEALTH_CHECK) + << "Standalone status was partially loaded, returning the following response: " + << degraded_response; + i_socket->writeData(curr_client_socket, degraded_response_buffer); + closeCurrentSocket(curr_client_socket, curr_routine_id); + return; + } + if (nginxContainerIsRunning()) { dbgDebug(D_HEALTH_CHECK) << "nginx conatiner is running, returning the following response: " diff --git a/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc b/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc index e6b4a69..c3c1396 100755 --- a/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc +++ b/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc @@ -194,7 +194,7 @@ TEST_F(HealthCheckerTest, connectionsLimit) connection_handler_routine(); EXPECT_THAT( - capture_debug.str(), HasSubstr("Cannot serve new client, reached maximun open connections") + capture_debug.str(), HasSubstr("Cannot serve new client, reached maximum open connections") ); } diff --git a/components/security_apps/orchestration/include/declarative_policy_utils.h b/components/security_apps/orchestration/include/declarative_policy_utils.h index c742124..461ba17 100644 --- a/components/security_apps/orchestration/include/declarative_policy_utils.h +++ b/components/security_apps/orchestration/include/declarative_policy_utils.h @@ -31,6 +31,14 @@ class ApplyPolicyEvent : public Event { public: ApplyPolicyEvent() {} + ApplyPolicyEvent(const std::string &path) : local_policy_path(path) {} + + // LCOV_EXCL_START Reason: no test exist + std::string getPolicyPath() const { return local_policy_path; } + // LCOV_EXCL_STOP + +private: + std::string local_policy_path; }; class DeclarativePolicyUtils @@ -40,6 +48,7 @@ class DeclarativePolicyUtils Singleton::Consume, Singleton::Consume, Singleton::Consume, + public Singleton::Consume, Singleton::Consume, public Listener { @@ -50,8 +59,7 @@ public: void doCall() override { - Singleton::Consume::by()->setPolicyPath(policy_path.get()); - ApplyPolicyEvent().notify(); + ApplyPolicyEvent(policy_path.get()).notify(); } private: @@ -80,6 +88,7 @@ public: private: std::string getCleanChecksum(const std::string &unclean_checksum); + std::string local_policy_path; std::string curr_version; std::string curr_policy; bool should_apply_policy; diff --git a/components/security_apps/orchestration/include/fog_authenticator.h b/components/security_apps/orchestration/include/fog_authenticator.h index 1bdc3f6..a80e593 100755 --- a/components/security_apps/orchestration/include/fog_authenticator.h +++ b/components/security_apps/orchestration/include/fog_authenticator.h @@ -142,6 +142,7 @@ protected: std::string base64Encode(const std::string &in) const; std::string buildBasicAuthHeader(const std::string &username, const std::string &pass) const; std::string buildOAuth2Header(const std::string &token) const; + std::string getUserEdition() const; // This apps which the orchestrations requires them from Fog. std::vector required_security_apps; diff --git a/components/security_apps/orchestration/include/get_status_rest.h b/components/security_apps/orchestration/include/get_status_rest.h index 655389f..d1b4a88 100755 --- a/components/security_apps/orchestration/include/get_status_rest.h +++ b/components/security_apps/orchestration/include/get_status_rest.h @@ -54,6 +54,7 @@ public: last_update = i_orch_status->getUpdateTime(); last_update_status = i_orch_status->getUpdateStatus(); policy_version = i_orch_status->getPolicyVersion(); + waap_model_version = i_orch_status->getWaapModelVersion(); last_policy_update = i_orch_status->getLastPolicyUpdate(); last_manifest_update = i_orch_status->getLastManifestUpdate(); last_settings_update = i_orch_status->getLastSettingsUpdate(); @@ -72,6 +73,7 @@ private: S2C_LABEL_PARAM(std::string, last_update, "Last update"); S2C_LABEL_PARAM(std::string, last_update_status, "Last update status"); S2C_LABEL_PARAM(std::string, policy_version, "Policy version"); + S2C_LABEL_PARAM(std::string, waap_model_version, "AI model version"); S2C_LABEL_PARAM(std::string, last_policy_update, "Last policy update"); S2C_LABEL_PARAM(std::string, last_manifest_update, "Last manifest update"); S2C_LABEL_PARAM(std::string, last_settings_update, "Last settings update"); diff --git a/components/security_apps/orchestration/include/mock/mock_orchestration_status.h b/components/security_apps/orchestration/include/mock/mock_orchestration_status.h index 740cfa5..a848973 100644 --- a/components/security_apps/orchestration/include/mock/mock_orchestration_status.h +++ b/components/security_apps/orchestration/include/mock/mock_orchestration_status.h @@ -45,6 +45,7 @@ public: MOCK_CONST_METHOD0(getUpdateTime, const std::string&()); MOCK_CONST_METHOD0(getLastManifestUpdate, const std::string&()); MOCK_CONST_METHOD0(getPolicyVersion, const std::string&()); + MOCK_CONST_METHOD0(getWaapModelVersion, const std::string&()); MOCK_CONST_METHOD0(getLastPolicyUpdate, const std::string&()); MOCK_CONST_METHOD0(getLastSettingsUpdate, const std::string&()); MOCK_CONST_METHOD0(getUpgradeMode, const std::string&()); diff --git a/components/security_apps/orchestration/include/namespace_data.h b/components/security_apps/orchestration/include/namespace_data.h new file mode 100644 index 0000000..a895467 --- /dev/null +++ b/components/security_apps/orchestration/include/namespace_data.h @@ -0,0 +1,35 @@ +// 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 __NAMESPACE_DATA_H__ +#define __NAMESPACE_DATA_H__ + +#include +#include + +#include "cereal/archives/json.hpp" +#include + +#include "rest.h" + +class NamespaceData : public ClientRest +{ +public: + bool loadJson(const std::string &json); + Maybe getNamespaceUidByName(const std::string &name); + +private: + std::map ns_name_to_uid; +}; + +#endif // __NAMESPACE_DATA_H__ diff --git a/components/security_apps/orchestration/manifest_controller/manifest_controller.cc b/components/security_apps/orchestration/manifest_controller/manifest_controller.cc index 7d5ae76..d2336c8 100755 --- a/components/security_apps/orchestration/manifest_controller/manifest_controller.cc +++ b/components/security_apps/orchestration/manifest_controller/manifest_controller.cc @@ -76,6 +76,7 @@ public: private: bool changeManifestFile(const string &new_manifest_file); + bool updateIgnoreListForNSaaS(); bool handlePackage( @@ -155,12 +156,36 @@ ManifestController::Impl::init() } } +bool +ManifestController::Impl::updateIgnoreListForNSaaS() +{ + if (!getProfileAgentSettingWithDefault(false, "accessControl.isAwsNSaaS")) return false; + + auto ignore_packages_path = getConfigurationWithDefault( + getFilesystemPathConfig() + "/conf/ignore-packages.txt", + "orchestration", + "Ignore packages list file path" + ); + ofstream ignore_file(ignore_packages_path); + if (!ignore_file.is_open()) { + dbgWarning(D_ORCHESTRATOR) << "Unable to open file " << ignore_packages_path << " for writing"; + return false; + } + + ignore_file << "all"; + ignore_file.close(); + dbgInfo(D_ORCHESTRATOR) << "Updated " << ignore_packages_path << " to ignore all packages"; + + return true; +} + bool ManifestController::Impl::updateManifest(const string &new_manifest_file) { auto i_env = Singleton::Consume::by(); auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF); auto orchestration_tools = Singleton::Consume::by(); + static bool ignore_packages_update = false; if (isIgnoreFile(new_manifest_file)) { if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) { @@ -173,9 +198,12 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file) dbgDebug(D_ORCHESTRATOR) << "Starting to update manifest file"; auto ignored_settings_packages = getProfileAgentSetting("orchestration.IgnoredPackagesList"); set packages_to_ignore = ignore_packages; - if (ignored_settings_packages.ok()) packages_to_ignore = *(*ignored_settings_packages); + if (ignored_settings_packages.ok()) { + packages_to_ignore = *(*ignored_settings_packages); + ignore_packages_update = false; + } - if (packages_to_ignore.count("all") > 0) { + if (ignore_packages_update || packages_to_ignore.count("all") > 0) { dbgTrace(D_ORCHESTRATOR) << "Nothing to update (\"ignore all\" turned on)"; if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) { @@ -315,6 +343,8 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file) if (all_installed && (any_installed || no_change) && no_corrupted_package) { manifest_file_update = changeManifestFile(new_manifest_file); + // In NSaaS - set ignore packages to any + ignore_packages_update = updateIgnoreListForNSaaS(); } else if (any_installed) { manifest_file_update = orchestration_tools->packagesToJsonFile(current_packages, manifest_file_path); } diff --git a/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc b/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc index 6c902ed..07eb0b9 100755 --- a/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc +++ b/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc @@ -11,6 +11,7 @@ #include "mock/mock_time_get.h" #include "mock/mock_orchestration_tools.h" #include "mock/mock_agent_details.h" +#include "mock/mock_details_resolver.h" #include "mock/mock_mainloop.h" #include "mock/mock_rest_api.h" @@ -38,9 +39,17 @@ public: .WillOnce(DoAll(SaveArg<2>(&routine), Return(1)) ); EXPECT_CALL(mock_tools, readFile(file_path)).WillOnce(Return(start_file_content)); + prepareResolvedDetails(); orchestration_status.init(); } + void + prepareResolvedDetails() + { + map resolved_details({{"AppSecModelVersion", waap_model}}); + EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_details)); + } + string orchestrationStatusFileToString() { @@ -82,7 +91,8 @@ public: const string ®istration_details_architecture = "", const string &agent_id = "None", const string &profile_id = "None", - const string &tenant_id = "None" + const string &tenant_id = "None", + const string &waap_model_version = "Advanced model" ) { return "{\n" @@ -91,6 +101,7 @@ public: " \"Last update\": \"" + last_update + "\",\n" " \"Last manifest update\": \"" + last_manifest_update + "\",\n" " \"Policy version\": \"" + policy_version + "\",\n" + " \"AI model version\": \"" + waap_model_version + "\",\n" " \"Last policy update\": \"" + last_policy_update + "\",\n" " \"Last settings update\": \"" + last_settings_update + "\",\n" " \"Upgrade mode\": \"" + upgrade_mode + "\",\n" @@ -118,12 +129,14 @@ public: ostringstream capture_debug; StrictMock mock_tools; StrictMock mock_agent_details; + StrictMock mock_details_resolver; OrchestrationStatus orchestration_status; I_OrchestrationStatus * i_orchestration_status = Singleton::Consume::from(orchestration_status); string file_path; Maybe start_file_content = genError("No file"); I_MainLoop::Routine routine; + string waap_model = "Advanced model"; }; TEST_F(OrchestrationStatusTest, doNothing) @@ -147,6 +160,7 @@ TEST_F(OrchestrationStatusTest, recoverFields) TEST_F(OrchestrationStatusTest, loadFromFile) { + prepareResolvedDetails(); Maybe status = genError("No file");; CPTestTempfile status_file; file_path = status_file.fname; @@ -214,12 +228,14 @@ TEST_F(OrchestrationStatusTest, recoveryFields) const string agent_id = "AgentId"; const string profile_id = "ProfileId"; const string tenant_id = "TenantId"; + auto fog_addr = Maybe(string("FogDomain")); EXPECT_CALL(mock_agent_details, getAgentId()).WillOnce(Return(agent_id)); EXPECT_CALL(mock_agent_details, getProfileId()).WillOnce(Return(profile_id)); EXPECT_CALL(mock_agent_details, getTenantId()).WillOnce(Return(tenant_id)); EXPECT_CALL(mock_agent_details, getFogDomain()).WillOnce(Return(fog_addr)); + i_orchestration_status->writeStatusToFile(); EXPECT_THAT(capture_debug.str(), HasSubstr("Repairing status fields")); @@ -227,6 +243,7 @@ TEST_F(OrchestrationStatusTest, recoveryFields) EXPECT_EQ(i_orchestration_status->getProfileId(), profile_id); EXPECT_EQ(i_orchestration_status->getTenantId(), tenant_id); EXPECT_EQ(i_orchestration_status->getFogAddress(), fog_addr.unpack()); + EXPECT_EQ(i_orchestration_status->getWaapModelVersion(), waap_model); } TEST_F(OrchestrationStatusTest, updateAllLastUpdatesTypes) @@ -419,6 +436,7 @@ TEST_F(OrchestrationStatusTest, setAllFields) " \"Last update\": \"current time\",\n" " \"Last manifest update\": \"current time\",\n" " \"Policy version\": \"12\",\n" + " \"AI model version\": \"Advanced model\",\n" " \"Last policy update\": \"current time\",\n" " \"Last settings update\": \"current time\",\n" " \"Upgrade mode\": \"Test Mode\",\n" diff --git a/components/security_apps/orchestration/modules/orchestration_status.cc b/components/security_apps/orchestration/modules/orchestration_status.cc index 183ca05..4a45a20 100755 --- a/components/security_apps/orchestration/modules/orchestration_status.cc +++ b/components/security_apps/orchestration/modules/orchestration_status.cc @@ -108,6 +108,7 @@ public: last_update_attempt = from.last_update_attempt; last_manifest_update = from.last_manifest_update; policy_version = from.policy_version; + waap_model_version = from.waap_model_version; last_policy_update = from.last_policy_update; last_settings_update = from.last_settings_update; upgrade_mode = from.upgrade_mode; @@ -128,6 +129,7 @@ public: const string & getUpdateTime() const { return last_update_time; } const string & getLastManifestUpdate() const { return last_manifest_update; } const string & getPolicyVersion() const { return policy_version; } + const string & getWaapModelVersion() const { return waap_model_version; } const string & getLastPolicyUpdate() const { return last_policy_update; } const string & getLastSettingsUpdate() const { return last_settings_update; } const string & getUpgradeMode() const { return upgrade_mode; } @@ -142,6 +144,16 @@ public: const map & getServicePolicies() const { return service_policies; } const map & getServiceSettings() const { return service_settings; } + void updateWaapModelVersion() { + map details_resolver = + Singleton::Consume::by()->getResolvedDetails(); + if (details_resolver.find("AppSecModelVersion") != details_resolver.end()) { + waap_model_version = details_resolver["AppSecModelVersion"]; + } else { + waap_model_version = "None"; + } + } + void insertServicePolicy(const string &key, const string &value) { @@ -267,12 +279,13 @@ public: last_manifest_update = "None"; last_policy_update = "None"; last_settings_update = "None"; + waap_model_version = "None"; fog_address = "None"; agent_id = "None"; profile_id = "None"; tenant_id = "None"; registration_status = "None"; - manifest_status = "None"; + manifest_status = getenv("CLOUDGUARD_APPSEC_STANDALONE") ? "Succeeded" : "None"; upgrade_mode = "None"; } @@ -292,6 +305,7 @@ public: } else { fog_address = "None"; } + updateWaapModelVersion(); } } @@ -304,6 +318,7 @@ public: archive(cereal::make_nvp("Last update", last_update_time)); archive(cereal::make_nvp("Last manifest update", last_manifest_update)); archive(cereal::make_nvp("Policy version", policy_version)); + archive(cereal::make_nvp("AI model version", waap_model_version)); archive(cereal::make_nvp("Last policy update", last_policy_update)); archive(cereal::make_nvp("Last settings update", last_settings_update)); archive(cereal::make_nvp("Upgrade mode", upgrade_mode)); @@ -331,6 +346,7 @@ public: archive.setNextName(nullptr); } + archive(cereal::make_nvp("AI model version", waap_model_version)); archive(cereal::make_nvp("Last policy update", last_policy_update)); archive(cereal::make_nvp("Last settings update", last_settings_update)); @@ -368,6 +384,7 @@ private: string last_update_attempt; string last_manifest_update; string policy_version; + string waap_model_version; string last_policy_update; string last_settings_update; string upgrade_mode; @@ -387,13 +404,14 @@ class OrchestrationStatus::Impl : Singleton::Provide::Fro { public: void - writeStatusToFile() + writeStatusToFile() override { auto orchestration_status_path = getConfigurationWithDefault( filesystem_prefix + "/conf/orchestration_status.json", "orchestration", "Orchestration status path" ); + status.updateWaapModelVersion(); auto write_result = orchestration_tools->objectToJsonFile(status, orchestration_status_path); if (!write_result) { @@ -497,6 +515,7 @@ private: const string & getUpdateTime() const override { return status.getUpdateTime(); } const string & getLastManifestUpdate() const override { return status.getLastManifestUpdate(); } const string & getPolicyVersion() const override { return status.getPolicyVersion(); } + const string & getWaapModelVersion() const override { return status.getWaapModelVersion(); } const string & getLastPolicyUpdate() const override { return status.getLastPolicyUpdate(); } const string & getLastSettingsUpdate() const override { return status.getLastSettingsUpdate(); } const string & getUpgradeMode() const override { return status.getUpgradeMode(); } diff --git a/components/security_apps/orchestration/orchestration_comp.cc b/components/security_apps/orchestration/orchestration_comp.cc index 771335b..710103c 100755 --- a/components/security_apps/orchestration/orchestration_comp.cc +++ b/components/security_apps/orchestration/orchestration_comp.cc @@ -189,6 +189,10 @@ public: "Orchestration runner", true ); + + auto orchestration_tools = Singleton::Consume::by(); + orchestration_tools->getClusterId(); + hybrid_mode_metric.init( "Watchdog Metrics", ReportIS::AudienceTeam::AGENT_CORE, @@ -198,7 +202,6 @@ public: ReportIS::Audience::INTERNAL ); hybrid_mode_metric.registerListener(); - auto orchestration_tools = Singleton::Consume::by(); orchestration_tools->loadTenantsFromDir( getConfigurationWithDefault(getFilesystemPathConfig() + "/conf/", "orchestration", "Conf dir") ); @@ -1485,6 +1488,9 @@ private: if (i_details_resolver->compareCheckpointVersion(8100, greater_equal())) { agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true"); } + if (i_details_resolver->compareCheckpointVersion(8200, greater_equal())) { + agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER82", "true"); + } #endif // gaia || smb if (agent_data_report == curr_agent_data_report) { diff --git a/components/security_apps/orchestration/orchestration_tools/CMakeLists.txt b/components/security_apps/orchestration/orchestration_tools/CMakeLists.txt index bed840f..08211d2 100755 --- a/components/security_apps/orchestration/orchestration_tools/CMakeLists.txt +++ b/components/security_apps/orchestration/orchestration_tools/CMakeLists.txt @@ -1,5 +1,5 @@ ADD_DEFINITIONS(-Wno-deprecated-declarations) -add_library(orchestration_tools orchestration_tools.cc) +add_library(orchestration_tools orchestration_tools.cc namespace_data.cc) #add_subdirectory(orchestration_tools_ut) diff --git a/components/security_apps/orchestration/orchestration_tools/namespace_data.cc b/components/security_apps/orchestration/orchestration_tools/namespace_data.cc new file mode 100644 index 0000000..9479ef3 --- /dev/null +++ b/components/security_apps/orchestration/orchestration_tools/namespace_data.cc @@ -0,0 +1,117 @@ +// 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 "namespace_data.h" + +using namespace std; + +USE_DEBUG_FLAG(D_ORCHESTRATOR); + +template +void +parseNameSpaceJSONKey( + const string &key_name, + T &value, + cereal::JSONInputArchive &archive_in, + const T &default_value = T()) +{ + try { + archive_in(cereal::make_nvp(key_name, value)); + } catch (const cereal::Exception &e) { + archive_in.setNextName(nullptr); + value = default_value; + dbgDebug(D_ORCHESTRATOR) + << "Could not parse the required key. Key: " + << key_name + << ", Error: " + << e.what(); + } +} + +class NamespaceMetadata +{ +public: + void + load(cereal::JSONInputArchive &archive_in) + { + dbgFlow(D_ORCHESTRATOR); + parseNameSpaceJSONKey("name", name, archive_in); + parseNameSpaceJSONKey("uid", uid, archive_in); + } + + const string & + getName() const + { + return name; + } + + const string & + getUID() const + { + return uid; + } + +private: + string name; + string uid; +}; + +class SingleNamespaceData +{ +public: + void + load(cereal::JSONInputArchive &archive_in) + { + parseNameSpaceJSONKey("metadata", metadata, archive_in); + } + + const NamespaceMetadata & + getMetadata() const + { + return metadata; + } + +private: + NamespaceMetadata metadata; +}; + +bool +NamespaceData::loadJson(const string &json) +{ + dbgFlow(D_ORCHESTRATOR); + string modified_json = json; + modified_json.pop_back(); + stringstream in; + in.str(modified_json); + try { + cereal::JSONInputArchive in_ar(in); + vector items; + in_ar(cereal::make_nvp("items", items)); + for (const SingleNamespaceData &single_ns_data : items) { + ns_name_to_uid[single_ns_data.getMetadata().getName()] = single_ns_data.getMetadata().getUID(); + } + } catch (cereal::Exception &e) { + dbgWarning(D_ORCHESTRATOR) << "Failed to load namespace data JSON. Error: " << e.what(); + return false; + } + return true; +} + +Maybe +NamespaceData::getNamespaceUidByName(const string &name) +{ + if (ns_name_to_uid.find(name) == ns_name_to_uid.end()) { + return genError("Namespace doesn't exist. Name: " + name); + } + return ns_name_to_uid.at(name); +} diff --git a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc index ff4d60a..952dac6 100755 --- a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc +++ b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc @@ -19,6 +19,7 @@ #include "cereal/types/vector.hpp" #include "cereal/types/set.hpp" #include "agent_core_utilities.h" +#include "namespace_data.h" #include #include @@ -47,11 +48,13 @@ public: const string &tenant_id, const string &profile_id) const override; + shared_ptr fileStreamWrapper(const std::string &path) const override; Maybe readFile(const string &path) const override; - bool writeFile(const string &text, const string &path) const override; + bool writeFile(const string &text, const string &path, bool append_mode = false) const override; bool removeFile(const string &path) const override; bool copyFile(const string &src_path, const string &dst_path) const override; bool doesFileExist(const string &file_path) const override; + void getClusterId() const override; void fillKeyInJson(const string &filename, const string &_key, const string &_val) const override; bool createDirectory(const string &directory_path) const override; bool doesDirectoryExist(const string &dir_path) const override; @@ -127,6 +130,98 @@ OrchestrationTools::Impl::fillKeyInJson(const string &filename, const string &_k } // LCOV_EXCL_STOP +bool +isPlaygroundEnv() +{ + const char *env_string = getenv("PLAYGROUND"); + + if (env_string == nullptr) return false; + string env_value = env_string; + transform(env_value.begin(), env_value.end(), env_value.begin(), ::tolower); + + return env_value == "true"; +} + +Maybe +getNamespaceDataFromCluster(const string &path) +{ + NamespaceData name_space; + string token = Singleton::Consume::by()->getToken(); + Flags conn_flags; + conn_flags.setFlag(MessageConnConfig::SECURE_CONN); + conn_flags.setFlag(MessageConnConfig::IGNORE_SSL_VALIDATION); + auto messaging = Singleton::Consume::by(); + bool res = messaging->sendObject( + name_space, + I_Messaging::Method::GET, + "kubernetes.default.svc", + 443, + conn_flags, + path, + "Authorization: Bearer " + token + "\nConnection: close" + ); + + if (res) return name_space; + + return genError(string("Was not able to get object form k8s cluser in path: " + path)); +} + +bool +doesClusterIdExists() +{ + string playground_uid = isPlaygroundEnv() ? "playground-" : ""; + + dbgTrace(D_ORCHESTRATOR) << "Getting cluster UID"; + + auto maybe_namespaces_data = getNamespaceDataFromCluster("/api/v1/namespaces/"); + + if (!maybe_namespaces_data.ok()) { + dbgWarning(D_ORCHESTRATOR) + << "Failed to retrieve K8S namespace data. Error: " + << maybe_namespaces_data.getErr(); + return false; + } + + NamespaceData namespaces_data = maybe_namespaces_data.unpack(); + + Maybe maybe_ns_uid = namespaces_data.getNamespaceUidByName("kube-system"); + if (!maybe_ns_uid.ok()) { + dbgWarning(D_ORCHESTRATOR) << maybe_ns_uid.getErr(); + return false; + } + string uid = playground_uid + maybe_ns_uid.unpack(); + dbgTrace(D_ORCHESTRATOR) << "Found k8s cluster UID: " << uid; + I_Environment *env = Singleton::Consume::by(); + env->getConfigurationContext().registerValue( + "k8sClusterId", + uid, + EnvKeyAttr::LogSection::SOURCE + ); + I_AgentDetails *i_agent_details = Singleton::Consume::by(); + i_agent_details->setClusterId(uid); + return true; +} + +void +OrchestrationTools::Impl::getClusterId() const +{ + auto env_type = Singleton::Consume::by()->getEnvType(); + + if (env_type == EnvType::K8S) { + Singleton::Consume::by()->addOneTimeRoutine( + I_MainLoop::RoutineType::Offline, + [this] () + { + while(!doesClusterIdExists()) { + Singleton::Consume::by()->yield(chrono::seconds(1)); + } + return; + }, + "Get k8s cluster ID" + ); + } +} + bool OrchestrationTools::Impl::doesFileExist(const string &file_path) const { @@ -140,7 +235,7 @@ OrchestrationTools::Impl::doesDirectoryExist(const string &dir_path) const } bool -OrchestrationTools::Impl::writeFile(const string &text, const string &path) const +OrchestrationTools::Impl::writeFile(const string &text, const string &path, bool append_mode) const { dbgDebug(D_ORCHESTRATOR) << "Writing file: text = " << text << ", path = " << path; if (path.find('/') != string::npos) { @@ -151,8 +246,15 @@ OrchestrationTools::Impl::writeFile(const string &text, const string &path) cons return false; } } + + ofstream fout; + + if (append_mode) { + fout.open(path, std::ios::app); + } else { + fout.open(path); + } try { - ofstream fout(path); fout << text; return true; } catch (const ofstream::failure &e) { @@ -186,6 +288,12 @@ OrchestrationTools::Impl::isNonEmptyFile(const string &path) const return false; } +shared_ptr +OrchestrationTools::Impl::fileStreamWrapper(const std::string &path) const +{ + return make_shared(path); +} + Maybe OrchestrationTools::Impl::readFile(const string &path) const { diff --git a/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc b/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc index c229aca..02581ed 100755 --- a/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc +++ b/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc @@ -1,8 +1,13 @@ #include "orchestration_tools.h" #include "cptest.h" +#include "config_component.h" #include "mock/mock_tenant_manager.h" #include "mock/mock_shell_cmd.h" +#include "mock/mock_messaging.h" +#include "mock/mock_env_details.h" +#include "mock/mock_agent_details.h" +#include "mock/mock_mainloop.h" using namespace std; using namespace testing; @@ -14,6 +19,17 @@ public: { } + string + getResource(const string &path) + { + string resource_path = cptestFnameInSrcDir(path); + ifstream resource_file(resource_path); + EXPECT_TRUE(resource_file.is_open()); + stringstream resource_file_content; + resource_file_content << resource_file.rdbuf(); + return resource_file_content.str(); + } + void cleanSpaces(string &str) { @@ -47,27 +63,74 @@ public: OrchestrationTools orchestration_tools; I_OrchestrationTools *i_orchestration_tools = Singleton::Consume::from(orchestration_tools); - StrictMock mock_tenant_manager; + NiceMock mock_messaging; + NiceMock mock_agent_details; + NiceMock mock_mainloop; StrictMock mock_shell_cmd; + StrictMock mock_env_details; + StrictMock mock_tenant_manager; + ::Environment env; + }; TEST_F(OrchestrationToolsTest, doNothing) { } +TEST_F(OrchestrationToolsTest, getClusterId) +{ + EXPECT_CALL(mock_env_details, getToken()).WillOnce(Return("123")); + EXPECT_CALL(mock_env_details, getEnvType()).WillOnce(Return(EnvType::K8S)); + I_MainLoop::Routine routine; + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::Offline, _, "Get k8s cluster ID", _) + ).WillOnce(DoAll(SaveArg<1>(&routine), Return(1))); + + string namespaces = getResource("k8s_namespaces.json"); + EXPECT_CALL( + mock_messaging, + sendMessage( + true, + "", + I_Messaging::Method::GET, + "kubernetes.default.svc", + 443, + _, + "/api/v1/namespaces/", + "Authorization: Bearer 123\nConnection: close", + _, + _ + ) + ).WillRepeatedly(Return(Maybe(namespaces))); + i_orchestration_tools->getClusterId(); + routine(); +} + TEST_F(OrchestrationToolsTest, writeReadTextToFile) { - EXPECT_TRUE(i_orchestration_tools->writeFile(manifest_text, manifest_file)); + EXPECT_TRUE(i_orchestration_tools->writeFile(manifest_text, manifest_file, false)); EXPECT_TRUE(i_orchestration_tools->doesFileExist(manifest_file)); EXPECT_TRUE(i_orchestration_tools->isNonEmptyFile(manifest_file)); + EXPECT_TRUE(i_orchestration_tools->fileStreamWrapper(manifest_file)->is_open()); EXPECT_EQ(manifest_text, i_orchestration_tools->readFile(manifest_file).unpack()); EXPECT_FALSE(i_orchestration_tools->isNonEmptyFile("no_such_file")); } +TEST_F(OrchestrationToolsTest, writeAndAppendToFile) +{ + EXPECT_TRUE(i_orchestration_tools->writeFile("blabla", "in_test.json", false)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist("in_test.json")); + EXPECT_TRUE(i_orchestration_tools->isNonEmptyFile("in_test.json")); + EXPECT_TRUE(i_orchestration_tools->writeFile(" Appending Text", "in_test.json", true)); + + EXPECT_EQ("blabla Appending Text", i_orchestration_tools->readFile("in_test.json").unpack());; +} + TEST_F(OrchestrationToolsTest, loadPackagesFromJsonTest) { - EXPECT_TRUE(i_orchestration_tools->writeFile("blabla", "in_test.json")); + EXPECT_TRUE(i_orchestration_tools->writeFile("blabla", "in_test.json", false)); string file_name = "in_test.json"; Maybe> packages = i_orchestration_tools->loadPackagesFromJson(file_name); EXPECT_FALSE(packages.ok()); @@ -83,7 +146,7 @@ TEST_F(OrchestrationToolsTest, loadPackagesFromJsonTest) TEST_F(OrchestrationToolsTest, copyFile) { - EXPECT_TRUE(i_orchestration_tools->writeFile("blabla", "in_test.json")); + EXPECT_TRUE(i_orchestration_tools->writeFile("blabla", "in_test.json", false)); EXPECT_TRUE(i_orchestration_tools->copyFile("in_test.json", "cpy_test.json")); EXPECT_EQ("blabla", i_orchestration_tools->readFile("cpy_test.json").unpack()); EXPECT_FALSE(i_orchestration_tools->copyFile("NOT_EXISTS_FILE", "cpy2_test.json")); @@ -199,7 +262,7 @@ TEST_F(OrchestrationToolsTest, jsonFileToPackages) " }" " ]" "}"; - i_orchestration_tools->writeFile(string_stream.str(), "packages_tmp.json"); + i_orchestration_tools->writeFile(string_stream.str(), "packages_tmp.json", false); Maybe> packages = i_orchestration_tools->loadPackagesFromJson("packages_tmp.json"); EXPECT_TRUE(packages.ok()); EXPECT_TRUE(packages.unpack().find("nano-agent") != packages.unpack().end()); @@ -222,7 +285,7 @@ TEST_F(OrchestrationToolsTest, packagesToJsonFile) " }" " ]" "}"; - i_orchestration_tools->writeFile(string_stream.str(), "packages.json"); + i_orchestration_tools->writeFile(string_stream.str(), "packages.json", false); Maybe> packages = i_orchestration_tools->loadPackagesFromJson("packages.json"); EXPECT_TRUE(packages.ok()); EXPECT_TRUE(i_orchestration_tools->packagesToJsonFile(packages.unpack(), "packages.json")); @@ -277,8 +340,8 @@ TEST_F(OrchestrationToolsTest, deleteVirtualTenantFiles) EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path)); string settings_file_path = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; - i_orchestration_tools->writeFile(string_stream.str(), settings_file_path); - i_orchestration_tools->writeFile(string_stream.str(), policy_file_path); + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path, false); + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path, false); EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path)); EXPECT_TRUE(i_orchestration_tools->doesFileExist(policy_file_path)); @@ -301,16 +364,16 @@ TEST_F(OrchestrationToolsTest, loadTenants) EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path2)); string settings_file_path1 = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; - i_orchestration_tools->writeFile(string_stream.str(), settings_file_path1); + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path1, false); string settings_file_path2 = conf_path + "/tenant_123456_profile_654321_settings.json"; - i_orchestration_tools->writeFile(string_stream.str(), settings_file_path2); + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path2, false); string policy_file_path1 = policy_folder_path1 + "/policy.json"; - i_orchestration_tools->writeFile(string_stream.str(), policy_file_path1); + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path1, false); string policy_file_path2 = policy_folder_path2 + "/policy.json"; - i_orchestration_tools->writeFile(string_stream.str(), policy_file_path2); + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path2, false); EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path1)); EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path2)); diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc index b118ddc..3d9c802 100644 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc @@ -62,6 +62,8 @@ public: addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true) ).WillOnce(DoAll(SaveArg<1>(&routine), Return(1))); + EXPECT_CALL(mock_orchestration_tools, getClusterId()); + EXPECT_CALL(mock_shell_cmd, getExecOutput("openssl version -d | cut -d\" \" -f2 | cut -d\"\\\"\" -f2", _, _)) .WillOnce(Return(string("OpenSSL certificates Directory"))); @@ -91,11 +93,11 @@ public: Maybe err = genError("No file exist"); EXPECT_CALL(mock_orchestration_tools, readFile("/etc/cp/conf/user-cred.json")).WillOnce(Return(err)); - EXPECT_CALL(mock_orchestration_tools, writeFile("This is fake", "/etc/cp/data/data1.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("This is fake", "/etc/cp/data/data1.a", false)).WillOnce( Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile("0000 is fake", "/etc/cp/data/data4.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("0000 is fake", "/etc/cp/data/data4.a", false)).WillOnce( Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile("This is 3333", "/etc/cp/data/data6.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("This is 3333", "/etc/cp/data/data6.a", false)).WillOnce( Return(true)); } diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc index d362fd6..88de151 100755 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc @@ -54,6 +54,8 @@ public: addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true) ).WillOnce(DoAll(SaveArg<1>(&routine), Return(1))); + EXPECT_CALL(mock_orchestration_tools, getClusterId()); + EXPECT_CALL( mock_shell_cmd, getExecOutput("openssl version -d | cut -d\" \" -f2 | cut -d\"\\\"\" -f2", _, _) @@ -118,11 +120,11 @@ public: Maybe err = genError("No file exist"); EXPECT_CALL(mock_orchestration_tools, readFile("/etc/cp/conf/user-cred.json")).WillOnce(Return(err)); - EXPECT_CALL(mock_orchestration_tools, writeFile("This is fake", "/etc/cp/data/data1.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("This is fake", "/etc/cp/data/data1.a", false)).WillOnce( Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile("0000 is fake", "/etc/cp/data/data4.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("0000 is fake", "/etc/cp/data/data4.a", false)).WillOnce( Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile("This is 3333", "/etc/cp/data/data6.a")).WillOnce( + EXPECT_CALL(mock_orchestration_tools, writeFile("This is 3333", "/etc/cp/data/data6.a", false)).WillOnce( Return(true)); } @@ -1333,26 +1335,6 @@ TEST_F(OrchestrationTest, manifestUpdate) } catch (const invalid_argument& e) {} } -TEST_F(OrchestrationTest, loadFromOrchestrationPolicy) -{ - EXPECT_CALL( - rest, - mockRestCall(RestAction::ADD, "proxy", _) - ).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler))); - waitForRestCall(); - init(); -} - -TEST_F(OrchestrationTest, loadFromOrchestrationBackupPolicy) -{ - EXPECT_CALL( - rest, - mockRestCall(RestAction::ADD, "proxy", _) - ).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler))); - waitForRestCall(); - init(); -} - TEST_F(OrchestrationTest, getBadPolicyUpdate) { EXPECT_CALL( @@ -1815,6 +1797,7 @@ TEST_F(OrchestrationTest, GetRestOrchStatus) " \"Last update\": \"" + test_str + "\",\n" " \"Last update status\": \"" + test_str + "\",\n" " \"Policy version\": \"" + test_str + "\",\n" + " \"AI model version\": \"" + test_str + "\",\n" " \"Last policy update\": \"" + test_str + "\",\n" " \"Last manifest update\": \"" + test_str + "\",\n" " \"Last settings update\": \"" + test_str + "\",\n" @@ -1841,6 +1824,7 @@ TEST_F(OrchestrationTest, GetRestOrchStatus) EXPECT_CALL(mock_status, getUpdateTime()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getLastManifestUpdate()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getPolicyVersion()).WillOnce(ReturnRef(test_str)); + EXPECT_CALL(mock_status, getWaapModelVersion()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getLastPolicyUpdate()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getLastSettingsUpdate()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getUpgradeMode()).WillOnce(ReturnRef(test_str)); diff --git a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc index 883a999..522ea39 100755 --- a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc +++ b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc @@ -246,7 +246,8 @@ TEST_F(ServiceControllerTest, UpdateConfiguration) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); @@ -357,8 +358,9 @@ TEST_F(ServiceControllerTest, supportVersions) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_versions_path)).WillOnce(Return(false)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile(versions, policy_versions_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(versions, policy_versions_path, false)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("versions", policy_versions_path, OrchestrationStatusConfigType::POLICY)); EXPECT_CALL(mock_orchestration_status, @@ -455,7 +457,8 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); @@ -575,7 +578,8 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); @@ -807,7 +811,8 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); @@ -965,7 +970,7 @@ TEST_F(ServiceControllerTest, backup) ).WillOnce(Return(true)); EXPECT_CALL( mock_orchestration_tools, - writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true) + writeFile(l4_firewall, l4_firewall_policy_path, false)).WillOnce(Return(true) ); EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension)) .WillOnce(Return(true)); @@ -1078,7 +1083,7 @@ TEST_F(ServiceControllerTest, backup_file_doesnt_exist) ).WillOnce(Return(true)); EXPECT_CALL( mock_orchestration_tools, - writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true) + writeFile(l4_firewall, l4_firewall_policy_path, false)).WillOnce(Return(true) ); // backup file doesn't exist so the copyFile function should be called 0 times @@ -1194,7 +1199,7 @@ TEST_F(ServiceControllerTest, backupAttempts) EXPECT_CALL( mock_orchestration_tools, - writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true) + writeFile(l4_firewall, l4_firewall_policy_path, false)).WillOnce(Return(true) ); EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension)) @@ -1311,8 +1316,10 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration) EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("orchestration", orchestration_policy_path, OrchestrationStatusConfigType::POLICY)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); - EXPECT_CALL(mock_orchestration_tools, writeFile(orchestration, orchestration_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(orchestration, orchestration_policy_path, false)) + .WillOnce(Return(true)); 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)); @@ -1560,7 +1567,12 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL( + mock_orchestration_tools, + writeFile( + l4_firewall, + l4_firewall_policy_path, + false)).WillOnce(Return(true)); EXPECT_CALL( mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY) @@ -1667,7 +1679,7 @@ TEST_F(ServiceControllerTest, errorWhileWrtingNewConfiguration) EXPECT_CALL( mock_orchestration_tools, - writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(false) + writeFile(l4_firewall, l4_firewall_policy_path, false)).WillOnce(Return(false) ); EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); @@ -1782,7 +1794,7 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles) EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path_new)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path_new)) + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path_new, false)) .WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration( @@ -1889,7 +1901,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); - EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)). + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)). WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_status, setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); diff --git a/components/security_apps/orchestration/update_communication/CMakeLists.txt b/components/security_apps/orchestration/update_communication/CMakeLists.txt index 94e0225..531f214 100755 --- a/components/security_apps/orchestration/update_communication/CMakeLists.txt +++ b/components/security_apps/orchestration/update_communication/CMakeLists.txt @@ -1,2 +1,2 @@ -add_library(update_communication update_communication.cc hybrid_communication.cc fog_communication.cc fog_authenticator.cc local_communication.cc declarative_policy_utils.cc) +add_library(update_communication update_communication.cc hybrid_communication.cc fog_communication.cc fog_authenticator.cc local_communication.cc declarative_policy_utils.cc fog_helper_open_source.cc) #add_subdirectory(update_communication_ut) diff --git a/components/security_apps/orchestration/update_communication/declarative_policy_utils.cc b/components/security_apps/orchestration/update_communication/declarative_policy_utils.cc index f5b5dae..52fcd44 100755 --- a/components/security_apps/orchestration/update_communication/declarative_policy_utils.cc +++ b/components/security_apps/orchestration/update_communication/declarative_policy_utils.cc @@ -16,6 +16,7 @@ USE_DEBUG_FLAG(D_ORCHESTRATOR); void DeclarativePolicyUtils::init() { + local_policy_path = getFilesystemPathConfig() + "/conf/local_policy.yaml"; should_apply_policy = true; Singleton::Consume::by()->addRestCall( RestAction::SET, "apply-policy" @@ -25,9 +26,10 @@ DeclarativePolicyUtils::init() // LCOV_EXCL_START Reason: no test exist void -DeclarativePolicyUtils::upon(const ApplyPolicyEvent &) +DeclarativePolicyUtils::upon(const ApplyPolicyEvent &event) { dbgTrace(D_ORCHESTRATOR) << "Apply policy event"; + local_policy_path = event.getPolicyPath(); should_apply_policy = true; } // LCOV_EXCL_STOP @@ -54,11 +56,9 @@ DeclarativePolicyUtils::getLocalPolicyChecksum() return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger"); } - string policy_path = Singleton::Consume::by()->getLocalPolicyPath(); - Maybe file_checksum = orchestration_tools->calculateChecksum( I_OrchestrationTools::SELECTED_CHECKSUM_TYPE, - policy_path + local_policy_path ); if (!file_checksum.ok()) { @@ -83,8 +83,11 @@ void DeclarativePolicyUtils::updateCurrentPolicy(const string &policy_checksum) { string clean_policy_checksum = getCleanChecksum(policy_checksum); - curr_policy = Singleton::Consume::by()->parsePolicy( - clean_policy_checksum + auto env = Singleton::Consume::by()->getEnvType(); + curr_policy = Singleton::Consume::by()->generateAppSecLocalPolicy( + env, + clean_policy_checksum, + local_policy_path ); } @@ -94,7 +97,7 @@ DeclarativePolicyUtils::getPolicyChecksum() I_OrchestrationTools *orchestration_tools = Singleton::Consume::by(); Maybe file_checksum = orchestration_tools->calculateChecksum( I_OrchestrationTools::SELECTED_CHECKSUM_TYPE, - Singleton::Consume::by()->getAgentPolicyPath() + "/tmp/local_appsec.policy" ); if (!file_checksum.ok()) { diff --git a/components/security_apps/orchestration/update_communication/fog_authenticator.cc b/components/security_apps/orchestration/update_communication/fog_authenticator.cc index 8522e1d..55ddfe8 100755 --- a/components/security_apps/orchestration/update_communication/fog_authenticator.cc +++ b/components/security_apps/orchestration/update_communication/fog_authenticator.cc @@ -187,6 +187,8 @@ FogAuthenticator::registerAgent( request << make_pair("managedMode", "management"); } + request << make_pair("userEdition", getUserEdition()); + if (details_resolver->isReverseProxy()) { request << make_pair("reverse_proxy", "true"); } @@ -207,6 +209,9 @@ FogAuthenticator::registerAgent( if (details_resolver->compareCheckpointVersion(8100, std::greater_equal())) { request << make_pair("isCheckpointVersionGER81", "true"); } + if (details_resolver->compareCheckpointVersion(8200, std::greater_equal())) { + request << make_pair("isCheckpointVersionGER82", "true"); + } #endif // gaia || smb auto fog_messaging = Singleton::Consume::by(); diff --git a/components/security_apps/orchestration/update_communication/fog_helper_open_source.cc b/components/security_apps/orchestration/update_communication/fog_helper_open_source.cc new file mode 100755 index 0000000..6b7de3a --- /dev/null +++ b/components/security_apps/orchestration/update_communication/fog_helper_open_source.cc @@ -0,0 +1,9 @@ +#include "fog_authenticator.h" + +#include + +std::string +FogAuthenticator::getUserEdition() const +{ + return "community"; +} diff --git a/components/security_apps/rate_limit/CMakeLists.txt b/components/security_apps/rate_limit/CMakeLists.txt new file mode 100644 index 0000000..15e7bbc --- /dev/null +++ b/components/security_apps/rate_limit/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(../waap/waap_clib) +include_directories(../waap/include) + +add_library(rate_limit_comp rate_limit.cc) + +add_library(rate_limit_config rate_limit_config.cc) diff --git a/components/security_apps/rate_limit/rate_limit.cc b/components/security_apps/rate_limit/rate_limit.cc new file mode 100755 index 0000000..a917b6f --- /dev/null +++ b/components/security_apps/rate_limit/rate_limit.cc @@ -0,0 +1,535 @@ +#include "rate_limit.h" + +#include +#include +#include + +#include "debug.h" +#include "i_environment.h" +#include "i_mainloop.h" +#include "i_time_get.h" +#include "rate_limit_config.h" +#include "nginx_attachment_common.h" +#include "http_inspection_events.h" +#include "Waf2Util.h" +#include "generic_rulebase/evaluators/asset_eval.h" +#include "WaapConfigApi.h" +#include "WaapConfigApplication.h" +#include "PatternMatcher.h" +#include "i_waapConfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hiredis/hiredis.h" + +USE_DEBUG_FLAG(D_RATE_LIMIT); + +using namespace std; + +enum class RateLimitVedict { ACCEPT, DROP, DROP_AND_LOG }; + +class RateLimit::Impl + : + public Listener +{ +public: + Impl() = default; + ~Impl() = default; + + Maybe + extractUri(const string &address) + { + size_t protocolPos = address.find("://"); + if (protocolPos == std::string::npos) return genError("Invalid URI format: " + address); + + size_t domainPos = address.find('/', protocolPos + 3); + if (domainPos == std::string::npos) return string(""); + + return address.substr(domainPos); + } + + bool + isRuleMatchingUri(const string &rule_uri, const string &request_uri, bool should_rule_be_exact_match) + { + if (rule_uri.find("*") != string::npos) { + // first condition is for 'exact match with wildcard' + // second is for when the rule serves as a prefix + bool wildcard_match = + !should_rule_be_exact_match && PatternMatcherWildcard(rule_uri + "*").match(request_uri + "/"); + wildcard_match |= PatternMatcherWildcard(rule_uri).match(request_uri); + return wildcard_match; + } + + return !should_rule_be_exact_match && str_starts_with(request_uri, rule_uri); + } + + Maybe + findRateLimitRule(const string &matched_uri, string &asset_id) + { + WaapConfigAPI api_config; + WaapConfigApplication application_config; + IWaapConfig* site_config = nullptr; + + if (WaapConfigAPI::getWaapAPIConfig(api_config)) { + site_config = &api_config; + } else if (WaapConfigApplication::getWaapSiteConfig(application_config)) { + site_config = &application_config; + } + + if (site_config == nullptr) return genError("Failed to get asset configuration. Skipping rate limit check."); + + asset_id = site_config->get_AssetId(); + ScopedContext rate_limit_ctx; + rate_limit_ctx.registerValue(AssetMatcher::ctx_key, site_config->get_AssetId()); + auto maybe_rate_limit_config = getConfiguration("rulebase", "rateLimit"); + if (!maybe_rate_limit_config.ok()) + return genError("Failed to get rate limit configuration. Skipping rate limit check."); + + const auto &rate_limit_config = maybe_rate_limit_config.unpack(); + mode = rate_limit_config.getRateLimitMode(); + + if (mode == "Inactive") return genError("Rate limit mode is Inactive in policy"); + + set rule_set; + Maybe matched_rule = genError("URI did not match any rate limit rule."); + int rate_limit_longest_match = 0; + for (const auto &application_url : site_config->get_applicationUrls()) { + dbgTrace(D_RATE_LIMIT) << "Application URL: " << application_url; + + auto maybe_uri = extractUri(application_url); + if (!maybe_uri.ok()) { + dbgWarning(D_RATE_LIMIT) << "Failed to extract URI from application URL: " << maybe_uri.getErr(); + continue; + } + + string application_uri = maybe_uri.unpack(); + if (application_uri.back() == '/') application_uri.pop_back(); + + for (const auto &rule : rate_limit_config.getRateLimitRules()) { + string full_rule_uri = application_uri + rule.getRateLimitUri(); + int full_rule_uri_length = full_rule_uri.length(); + + // avoiding duplicates + if (!rule_set.insert(full_rule_uri).second) continue; + + dbgTrace(D_RATE_LIMIT) + << "Trying to match rule uri: " + << full_rule_uri + << " with request uri: " + << matched_uri; + + if (full_rule_uri_length < rate_limit_longest_match) { + dbgDebug(D_RATE_LIMIT) + << "rule is shorter then already matched rule. current rule length: " + << full_rule_uri_length + << ", previously longest matched rule length: " + << rate_limit_longest_match; + continue; + } + + if (full_rule_uri == matched_uri || + full_rule_uri == matched_uri + "/" || + full_rule_uri + "/" == matched_uri) { + dbgDebug(D_RATE_LIMIT) + << "Found Exact match to request uri: " + << matched_uri + << ", rule uri: " + << full_rule_uri; + return rule; + } + + if (rule.getRateLimitUri() == "/") { + dbgDebug(D_RATE_LIMIT) + << "Matched new longest rule, request uri: " + << matched_uri + << ", rule uri: " + << full_rule_uri; + matched_rule = rule; + rate_limit_longest_match = full_rule_uri_length; + continue; + } + + if (isRuleMatchingUri(full_rule_uri, matched_uri, rule.isExactMatch())) { + dbgDebug(D_RATE_LIMIT) + << "Matched new longest rule, request uri: " + << matched_uri + << ", rule uri: " + << full_rule_uri; + matched_rule = rule; + rate_limit_longest_match = full_rule_uri_length; + } + } + } + + return matched_rule; + } + + EventVerdict + respond(const HttpRequestHeaderEvent &event) override + { + if (!event.isLastHeader()) return INSPECT; + + auto uri_ctx = Singleton::Consume::by()->get(HttpTransactionData::uri_ctx); + if (!uri_ctx.ok()) { + dbgWarning(D_RATE_LIMIT) << "Unable to get URL from context, Not enforcing rate limit"; + return ACCEPT; + } + + string asset_id; + auto uri = uri_ctx.unpack(); + transform(uri.begin(), uri.end(), uri.begin(), [](unsigned char c) { return tolower(c); }); + auto maybe_rule = findRateLimitRule(uri, asset_id); + if (!maybe_rule.ok()) { + dbgDebug(D_RATE_LIMIT) << "Not Enforcing Rate Limit: " << maybe_rule.getErr(); + return ACCEPT; + } + + const auto &rule = maybe_rule.unpack(); + burst = rule.getRateLimit(); + limit = static_cast(rule.getRateLimit()) / (rule.getRateLimitScope() == "Minute" ? 60 : 1); + + dbgTrace(D_RATE_LIMIT) + << "found rate limit rule with: " + << rule.getRateLimit() + << " per " + << (rule.getRateLimitScope() == "Minute" ? 60 : 1) + << " seconds"; + + auto maybe_source_identifier = + Singleton::Consume::by()->get(HttpTransactionData::source_identifier); + if (!maybe_source_identifier.ok()) { + dbgWarning(D_RATE_LIMIT) << "Unable to get source identifier from context, not enforcing rate limit"; + return ACCEPT; + } + + auto &source_identifier = maybe_source_identifier.unpack(); + dbgDebug(D_RATE_LIMIT) << "source identifier value: " << source_identifier; + + string unique_key = asset_id + ":" + source_identifier + ":" + uri; + if (unique_key.back() == '/') unique_key.pop_back(); + + auto verdict = decide(unique_key); + if (verdict == RateLimitVedict::ACCEPT) { + dbgTrace(D_RATE_LIMIT) << "Received ACCEPT verdict."; + return ACCEPT; + } + + if (verdict == RateLimitVedict::DROP_AND_LOG) sendLog(uri, source_identifier, rule); + + if (mode == "Active") { + dbgTrace(D_RATE_LIMIT) << "Received DROP verdict, this request will be blocked by rate limit"; + return DROP; + } + + dbgTrace(D_RATE_LIMIT) << "Received DROP in detect mode, will not block."; + return ACCEPT; + } + + string + getListenerName() const override + { + return "rate limit"; + } + + RateLimitVedict + decide(const std::string &key) { + if (redis == nullptr) { + dbgDebug(D_RATE_LIMIT) + << "there is no connection to the redis at the moment, unable to enforce rate limit"; + reconnectRedis(); + return RateLimitVedict::ACCEPT; + } + + redisReply* reply = static_cast(redisCommand(redis, "EVALSHA %s 1 %s %f %d", + rate_limit_lua_script_hash.c_str(), key.c_str(), limit, burst)); + + if (reply == NULL || redis->err) { + dbgDebug(D_RATE_LIMIT) + << "Error executing Redis command: No reply received, unable to enforce rate limit"; + reconnectRedis(); + return RateLimitVedict::ACCEPT; + } + + // redis's lua script returned true - accept + if (reply->type == REDIS_REPLY_INTEGER) { + freeReplyObject(reply); + return RateLimitVedict::ACCEPT; + } + + // redis's lua script returned false - drop, no need to log + if (reply->type == REDIS_REPLY_NIL) { + freeReplyObject(reply); + return RateLimitVedict::DROP; + } + + // redis's lua script returned string - drop and send log + const char* log_str = "BLOCK AND LOG"; + if (reply->type == REDIS_REPLY_STRING && strncmp(reply->str, log_str, strlen(log_str)) == 0) { + freeReplyObject(reply); + return RateLimitVedict::DROP_AND_LOG; + } + + dbgDebug(D_RATE_LIMIT) + << "Got unexected reply from redis. reply type: " + << reply->type + << ". not enforcing rate limit for this request."; + freeReplyObject(reply); + return RateLimitVedict::ACCEPT; + } + + void + sendLog(const string &uri, const string &source_identifier, const RateLimitRule& rule) + { + set rate_limit_triggers_set; + for (const auto &trigger : rule.getRateLimitTriggers()) { + rate_limit_triggers_set.insert(trigger.getTriggerId()); + } + + ScopedContext ctx; + ctx.registerValue>(TriggerMatcher::ctx_key, rate_limit_triggers_set); + auto log_trigger = getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log"); + + if (!log_trigger.isPreventLogActive(LogTriggerConf::SecurityType::AccessControl)) { + dbgTrace(D_RATE_LIMIT) << "Not sending rate-limit log as it is not required"; + return; + } + + auto maybe_rule_by_ctx = getConfiguration("rulebase", "rulesConfig"); + if (!maybe_rule_by_ctx.ok()) { + dbgWarning(D_RATE_LIMIT) + << "rule was not found by the given context. Reason: " + << maybe_rule_by_ctx.getErr(); + return; + } + + string event_name = "Rate limit"; + + LogGen log = log_trigger( + event_name, + LogTriggerConf::SecurityType::AccessControl, + ReportIS::Severity::HIGH, + ReportIS::Priority::HIGH, + true, + LogField("practiceType", "Rate Limit"), + ReportIS::Tags::RATE_LIMIT + ); + + const auto &rule_by_ctx = maybe_rule_by_ctx.unpack(); + + log + << LogField("assetId", rule_by_ctx.getAssetId()) + << LogField("assetName", rule_by_ctx.getAssetName()) + << LogField("ruleId", rule_by_ctx.getRuleId()) + << LogField("ruleName", rule_by_ctx.getRuleName()) + << LogField("httpUriPath", uri) + << LogField("httpSourceId", source_identifier) + << LogField("securityAction", (mode == "Active" ? "Prevent" : "Detect")) + << LogField("waapIncidentType", "Rate Limit"); + + auto http_method = + Singleton::Consume::by()->get(HttpTransactionData::method_ctx); + if (http_method.ok()) log << LogField("httpMethod", http_method.unpack()); + + auto http_host = + Singleton::Consume::by()->get(HttpTransactionData::host_name_ctx); + if (http_host.ok()) log << LogField("httpHostName", http_host.unpack()); + + auto source_ip = + Singleton::Consume::by()->get(HttpTransactionData::client_ip_ctx); + if (source_ip.ok()) log << LogField("sourceIP", ipAddrToStr(source_ip.unpack())); + + auto proxy_ip = + Singleton::Consume::by()->get(HttpTransactionData::proxy_ip_ctx); + if (proxy_ip.ok() && source_ip.ok() && ipAddrToStr(source_ip.unpack()) != proxy_ip.unpack()) { + log << LogField("proxyIP", static_cast(proxy_ip.unpack())); + } + } + + string + ipAddrToStr(const IPAddr& ip_address) const + { + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ip_address), str, INET_ADDRSTRLEN); + return string(str); + } + + Maybe + connectRedis() + { + disconnectRedis(); + + redisOptions options; + memset(&options, 0, sizeof(redisOptions)); + REDIS_OPTIONS_SET_TCP( + &options, + "127.0.0.1", + getConfigurationWithDefault(6379, "connection", "Redis Port") + ); + + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = getConfigurationWithDefault(30000, "connection", "Redis Timeout"); + options.connect_timeout = &timeout; + options.command_timeout = &timeout; + + redisContext* context = redisConnectWithOptions(&options); + if (context != nullptr && context->err) { + dbgDebug(D_RATE_LIMIT) + << "Error connecting to Redis: " + << context->errstr; + redisFree(context); + return genError(""); + } + + if (context == nullptr) return genError(""); + + redis = context; + static string luaScript = R"( + local key = KEYS[1] + local rateLimit = tonumber(ARGV[1]) + local burstLimit = tonumber(ARGV[2]) + local currentTimeSeconds = tonumber(redis.call('time')[1]) + local lastRequestTimeSeconds = tonumber(redis.call('get', key .. ':lastRequestTime') or "0") + local elapsedTimeSeconds = currentTimeSeconds - lastRequestTimeSeconds + local tokens = tonumber(redis.call('get', key .. ':tokens') or burstLimit) + local was_blocked = tonumber(redis.call('get', key .. ':block') or "0") + + tokens = math.min(tokens + (elapsedTimeSeconds * rateLimit), burstLimit) + + if tokens >= 1 then + tokens = tokens - 1 + redis.call('set', key .. ':tokens', tokens) + redis.call('set', key .. ':lastRequestTime', currentTimeSeconds) + redis.call('expire', key .. ':tokens', 60) + redis.call('expire', key .. ':lastRequestTime', 60) + return true + elseif was_blocked == 1 then + redis.call('set', key .. ':block', 1) + redis.call('expire', key .. ':block', 60) + return false + else + redis.call('set', key .. ':block', 1) + redis.call('expire', key .. ':block', 60) + return "BLOCK AND LOG" + end + )"; + + // Load the Lua script in Redis and retrieve its SHA1 hash + redisReply* loadReply = + static_cast(redisCommand(redis, "SCRIPT LOAD %s", luaScript.c_str())); + if (loadReply != nullptr && loadReply->type == REDIS_REPLY_STRING) { + rate_limit_lua_script_hash = loadReply->str; + freeReplyObject(loadReply); + } + + return Maybe(); + } + + void + reconnectRedis() + { + dbgFlow(D_RATE_LIMIT) << "Trying to reconnect to redis after failure to invoke a redis command"; + static bool is_reconnecting = false; + if (!is_reconnecting) { + is_reconnecting = true; + Singleton::Consume::by()->addOneTimeRoutine( + I_MainLoop::RoutineType::System, + [this] () + { + connectRedis(); + is_reconnecting = false; + }, + "Reconnect redis", + false + ); + } + + } + + void + handleNewPolicy() + { + if (RateLimitConfig::isActive() && !redis) { + connectRedis(); + registerListener(); + return; + } + + if (!RateLimitConfig::isActive()) { + disconnectRedis(); + unregisterListener(); + } + } + + void + disconnectRedis() + { + if (redis) { + redisFree(redis); + redis = nullptr; + } + } + + void + init() + { + Singleton::Consume::by()->addOneTimeRoutine( + I_MainLoop::RoutineType::System, + [this] () + { + handleNewPolicy(); + registerConfigLoadCb([this]() { handleNewPolicy(); }); + }, + "Initialize rate limit component", + false + ); + } + + void + fini() + { + disconnectRedis(); + } + +private: + static constexpr auto DROP = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP; + static constexpr auto ACCEPT = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT; + static constexpr auto INSPECT = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT; + + string mode; + string rate_limit_lua_script_hash; + int burst; + float limit; + redisContext* redis = nullptr; +}; + +RateLimit::RateLimit() : Component("RateLimit"), pimpl(make_unique()) {} + +RateLimit::~RateLimit() = default; + +void +RateLimit::preload() +{ + registerExpectedConfiguration("WAAP", "WebApplicationSecurity"); + registerExpectedConfiguration("WAAP", "WebAPISecurity"); + registerExpectedConfigFile("waap", Config::ConfigFileType::Policy); + registerExpectedConfiguration("rulebase", "rateLimit"); + registerExpectedConfigFile("accessControlV2", Config::ConfigFileType::Policy); + registerConfigPrepareCb([]() { RateLimitConfig::resetIsActive(); }); +} + +void +RateLimit::init() { pimpl->init(); } + +void +RateLimit::fini() { pimpl->fini(); } diff --git a/components/security_apps/rate_limit/rate_limit_config.cc b/components/security_apps/rate_limit/rate_limit_config.cc new file mode 100755 index 0000000..7084320 --- /dev/null +++ b/components/security_apps/rate_limit/rate_limit_config.cc @@ -0,0 +1,157 @@ +#include "rate_limit_config.h" + +bool RateLimitConfig::is_active = false; + +void +RateLimitTrigger::load(cereal::JSONInputArchive &ar) +{ + dbgTrace(D_REVERSE_PROXY) << "Serializing single Rate Limit rule's triggers"; + try { + ar(cereal::make_nvp("id", id)); + } catch (const cereal::Exception &e) { + dbgWarning(D_REVERSE_PROXY) + << "Failed to load single Rate Limit JSON rule's triggers. Error: " << e.what(); + ar.setNextName(nullptr); + } +} + +void +RateLimitRule::load(cereal::JSONInputArchive &ar) +{ + dbgTrace(D_REVERSE_PROXY) << "Serializing single Rate Limit rule"; + try { + ar(cereal::make_nvp("URI", uri)); + ar(cereal::make_nvp("scope", scope)); + ar(cereal::make_nvp("limit", limit)); + ar(cereal::make_nvp("triggers", rate_limit_triggers)); + } catch (const cereal::Exception &e) { + dbgWarning(D_REVERSE_PROXY) << "Failed to load single Rate Limit JSON rule. Error: " << e.what(); + ar.setNextName(nullptr); + } +} + +void +RateLimitRule::prepare(const std::string &asset_id, int zone_id) +{ + std::string zone_id_s = std::to_string(zone_id); + std::string zone; + if (isRootLocation()) { + zone = "root_zone_" + asset_id + "_" + zone_id_s; + } else { + std::string zone_name_suffix = uri; + std::replace(zone_name_suffix.begin(), zone_name_suffix.end(), '/', '_'); + zone = "zone" + zone_name_suffix + "_" + zone_id_s; + } + + limit_req_template_value = "zone=" + zone + " burst=" + std::to_string(limit) + " nodelay"; + + // nginx conf will look like: limit_req_zone zone=_:10m rate=r/; + std::string rate_unit = scope == "Minute" ? "r/m" : "r/s"; + limit_req_zone_template_value = + "zone=" + zone + ":" + cache_size + " rate=" + std::to_string(limit) + rate_unit; + + dbgTrace(D_REVERSE_PROXY) + << "limit_req_zone nginx template value: " + << limit_req_zone_template_value + << ", limit_req nginx template value: " + << limit_req_template_value; +} + +bool +RateLimitRule::isRootLocation() const +{ + if (uri.empty()) { + return false; + } + + auto non_root = uri.find_first_not_of("/"); + if (non_root != std::string::npos) { + return false; + } + return true; +} + +void +RateLimitConfig::load(cereal::JSONInputArchive &ar) +{ + dbgTrace(D_REVERSE_PROXY) << "Serializing Rate Limit config"; + try { + ar(cereal::make_nvp("rules", rate_limit_rules)); + ar(cereal::make_nvp("mode", mode)); + prepare(); + } catch (const cereal::Exception &e) { + dbgWarning(D_REVERSE_PROXY) << "Failed to load single Rate Limit JSON config. Error: " << e.what(); + ar.setNextName(nullptr); + } +} + +void +RateLimitConfig::addSiblingRateLimitRule(RateLimitRule &rule) { + rule.setExactMatch(); + RateLimitRule sibling_rule(rule); + sibling_rule.appendSlash(); + sibling_rule.setExactMatch(); + rate_limit_rules.push_back(sibling_rule); +} + +void +RateLimitConfig::prepare() +{ + // Removes invalid rules + auto last_valid_rule = + std::remove_if( + rate_limit_rules.begin(), + rate_limit_rules.end(), + [](const RateLimitRule &rule) { return !rule; } + ); + + rate_limit_rules.erase(last_valid_rule, rate_limit_rules.end()); + + // Removes duplicates + sort(rate_limit_rules.begin(), rate_limit_rules.end()); + rate_limit_rules.erase(std::unique(rate_limit_rules.begin(), rate_limit_rules.end()), rate_limit_rules.end()); + + std::for_each( + rate_limit_rules.begin(), + rate_limit_rules.end(), + [this](RateLimitRule &rule) { if (rule.isExactMatch()) { addSiblingRateLimitRule(rule); } } + ); + + dbgTrace(D_REVERSE_PROXY) + << "Final rate-limit rules: " + << makeSeparatedStr(rate_limit_rules, "; ") + << "; Mode: " + << mode; + + setIsActive(mode != "Inactive"); +} + +const RateLimitRule +RateLimitConfig::findLongestMatchingRule(const std::string &nginx_uri) const +{ + dbgFlow(D_REVERSE_PROXY) << "Trying to find a matching rat-limit rule for NGINX URI: " << nginx_uri; + + size_t longest_len = 0; + RateLimitRule longest_matching_rule; + for (const RateLimitRule &rule : rate_limit_rules) { + if (rule.getRateLimitUri() == nginx_uri) { + dbgTrace(D_REVERSE_PROXY) << "Found exact rate-limit match: " << rule; + return rule; + } + + if (nginx_uri.size() < rule.getRateLimitUri().size()) { + continue; + } + + if (std::equal(rule.getRateLimitUri().rbegin(), rule.getRateLimitUri().rend(), nginx_uri.rbegin())) { + if (rule.getRateLimitUri().size() > longest_len) { + longest_matching_rule = rule; + longest_len = rule.getRateLimitUri().size(); + dbgTrace(D_REVERSE_PROXY) << "Longest matching rate-limit rule so far: " << rule; + } + } + } + + dbgTrace(D_REVERSE_PROXY) << "Longest matching rate-limit rule: " << longest_matching_rule; + return longest_matching_rule; +} diff --git a/components/security_apps/waap/include/i_waapConfig.h b/components/security_apps/waap/include/i_waapConfig.h index 27eecbc..b8a1b4f 100755 --- a/components/security_apps/waap/include/i_waapConfig.h +++ b/components/security_apps/waap/include/i_waapConfig.h @@ -52,6 +52,7 @@ public: virtual const std::string& get_RuleName() const = 0; virtual const bool& get_WebAttackMitigation() const = 0; virtual const std::string& get_WebAttackMitigationAction() const = 0; + virtual const std::vector & get_applicationUrls() const = 0; virtual const std::shared_ptr& get_OverridePolicy() const = 0; virtual const std::shared_ptr& get_TriggerPolicy() const = 0; diff --git a/components/security_apps/waap/waap_clib/WaapConfigBase.cc b/components/security_apps/waap/waap_clib/WaapConfigBase.cc index 9d42f6a..910083d 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigBase.cc +++ b/components/security_apps/waap/waap_clib/WaapConfigBase.cc @@ -253,6 +253,12 @@ void WaapConfigBase::loadOpenRedirectPolicy(cereal::JSONInputArchive& ar) } +const std::vector & +WaapConfigBase::get_applicationUrls() const +{ + return m_applicationUrls; +} + void WaapConfigBase::loadErrorDisclosurePolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Information Disclosure policy"; diff --git a/components/security_apps/waap/waap_clib/WaapConfigBase.h b/components/security_apps/waap/waap_clib/WaapConfigBase.h index 2cae5f2..55d3fd1 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigBase.h +++ b/components/security_apps/waap/waap_clib/WaapConfigBase.h @@ -45,6 +45,7 @@ public: virtual const std::string& get_RuleName() const; virtual const bool& get_WebAttackMitigation() const; virtual const std::string& get_WebAttackMitigationAction() const; + virtual const std::vector & get_applicationUrls() const; virtual const std::shared_ptr& get_OverridePolicy() const; virtual const std::shared_ptr& get_TriggerPolicy() const; diff --git a/core/agent_core_utilities/agent_core_utilities.cc b/core/agent_core_utilities/agent_core_utilities.cc index 9488d32..44fe109 100755 --- a/core/agent_core_utilities/agent_core_utilities.cc +++ b/core/agent_core_utilities/agent_core_utilities.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "debug.h" @@ -49,6 +50,24 @@ exists(const string &path) return false; } +bool +isDirectory(const string &path) +{ + dbgFlow(D_INFRA_UTILS) << "Checking if path is a directory. Path: " << path; + struct stat buffer; + if (stat(path.c_str(), &buffer) != 0) { + dbgTrace(D_INFRA_UTILS) << "Path does not exists. Path: " << path; + return false; + } + + if (buffer.st_mode & S_IFDIR) { + dbgTrace(D_INFRA_UTILS) << "Path is a directory. Path: " << path; + return true; + } + + return false; +} + bool makeDir(const string &path, mode_t permission) { @@ -356,4 +375,20 @@ regexReplace(const char *file, int line, const string &sample, const regex ®e }// namespace Regex +namespace Strings +{ + +string +removeTrailingWhitespaces(string str) +{ + str.erase( + find_if(str.rbegin(), str.rend(), [] (char c) { return !isspace(c); }).base(), + str.end() + ); + + return str; +} + +} // namespace Strings + } // namespace NGEN diff --git a/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc b/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc index 5476f13..bbf86ac 100644 --- a/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc +++ b/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc @@ -98,8 +98,20 @@ TEST_F(AgentCoreUtilUT, printTest) EXPECT_EQ(NGEN::Filesystem::convertToHumanReadable(1024*gigabyte), "1024.00 GB"); } - TEST_F(AgentCoreUtilUT, fileBasenameTest) { EXPECT_EQ(NGEN::Filesystem::getFileName("/test/base/file/name"), "name"); } + +TEST_F(AgentCoreUtilUT, isDirectoryTest) +{ + mkdir("./test", 0400); + EXPECT_EQ(NGEN::Filesystem::isDirectory("/test/base/file/name"), false); + EXPECT_EQ(NGEN::Filesystem::isDirectory("./test"), true); +} + +TEST_F(AgentCoreUtilUT, removeTrailingWhitespacesTest) +{ + string str_with_trailing_whitespace = "str_with_trailing_whitespace\n\n\n\r \n\n\r"; + EXPECT_EQ(NGEN::Strings::removeTrailingWhitespaces(str_with_trailing_whitespace), "str_with_trailing_whitespace"); +} diff --git a/core/environment/environment.cc b/core/environment/environment.cc index 589f4d5..4c4af12 100644 --- a/core/environment/environment.cc +++ b/core/environment/environment.cc @@ -141,7 +141,6 @@ Environment::Impl::init() void Environment::Impl::fini() { - global.deactivate(); } void diff --git a/core/include/services_sdk/resources/report/report_enums.h b/core/include/services_sdk/resources/report/report_enums.h index 6285eea..6421991 100755 --- a/core/include/services_sdk/resources/report/report_enums.h +++ b/core/include/services_sdk/resources/report/report_enums.h @@ -143,7 +143,8 @@ enum class Notification { SDWAN_POLICY_UPDATE, SDWAN_POLICY_UPDATE_ERROR, SDWAN_POLICY_UPDATE_LOG, - SDWAN_POLICY_UPDATE_ERROR_LOG + SDWAN_POLICY_UPDATE_ERROR_LOG, + SDWAN_POLICY_WARNING_LOG }; enum class IssuingEngine { diff --git a/core/include/services_sdk/utilities/agent_core_utilities.h b/core/include/services_sdk/utilities/agent_core_utilities.h index 19b0e67..b4bb353 100755 --- a/core/include/services_sdk/utilities/agent_core_utilities.h +++ b/core/include/services_sdk/utilities/agent_core_utilities.h @@ -25,6 +25,7 @@ namespace Filesystem { bool exists(const std::string &path); +bool isDirectory(const std::string &path); bool makeDir(const std::string &path, mode_t permission = S_IRWXU); bool makeDirRecursive(const std::string &path, mode_t permission = S_IRWXU); @@ -75,6 +76,13 @@ regexReplace( } // namespace Regex +namespace Strings +{ + +std::string removeTrailingWhitespaces(std::string str); + +} // namespace Strings + } // namespace NGEN #endif // __AGENT_CORE_UTILITIES_H__ diff --git a/core/logging/log_generator.cc b/core/logging/log_generator.cc index 7977c21..b79111d 100755 --- a/core/logging/log_generator.cc +++ b/core/logging/log_generator.cc @@ -19,7 +19,10 @@ extern const string unnamed_service; LogGen::~LogGen() { - if (send_log) Singleton::Consume::by()->sendLog(log); + try { + if (send_log) Singleton::Consume::by()->sendLog(log); + } catch (...) { + } } LogGen & diff --git a/core/report/tag_and_enum_management.cc b/core/report/tag_and_enum_management.cc index 81b3b9e..13b991b 100755 --- a/core/report/tag_and_enum_management.cc +++ b/core/report/tag_and_enum_management.cc @@ -252,6 +252,7 @@ TagAndEnumManagement::convertToString(const Notification ¬ification) case Notification::SDWAN_POLICY_UPDATE_ERROR: return "8d2db6ea-30b7-11ec-8d3d-0242ac130003"; case Notification::SDWAN_POLICY_UPDATE_LOG: return "97cb79e1-e873-4f28-b123-5e19f8dd6f99"; case Notification::SDWAN_POLICY_UPDATE_ERROR_LOG: return "44ca5755-07a2-483c-b756-b7df444e175c"; + case Notification::SDWAN_POLICY_WARNING_LOG: return "c58d490e-6aa0-43da-bfaa-7edad0a57b7a"; } dbgAssert(false) << "Reached impossible notification value of: " << static_cast(notification); diff --git a/nodes/http_transaction_handler/CMakeLists.txt b/nodes/http_transaction_handler/CMakeLists.txt index ba6907e..cf999e2 100755 --- a/nodes/http_transaction_handler/CMakeLists.txt +++ b/nodes/http_transaction_handler/CMakeLists.txt @@ -14,6 +14,7 @@ target_link_libraries(cp-nano-http-transaction-handler pcre2-8 pcre2-posix yajl_s + hiredis -lshmem_ipc -lnginx_attachment_util @@ -32,6 +33,8 @@ target_link_libraries(cp-nano-http-transaction-handler waap waap_clib reputation + rate_limit_comp + rate_limit_config ips keywords l7_access_control @@ -53,6 +56,12 @@ execute_process ( ) install(FILES ${pcre2-posix} DESTINATION http_transaction_handler_service/lib) +execute_process ( + COMMAND bash -c "find /usr/lib -name \"libhiredis.so*\" | awk '{printf $0\";\"}'" + OUTPUT_VARIABLE hiredis +) +install(FILES ${hiredis} DESTINATION http_transaction_handler_service/lib) + execute_process ( COMMAND bash -c "find /usr/lib -name \"libxml2.so*\" | awk '{printf \$0\";\"}'" OUTPUT_VARIABLE xml2 diff --git a/nodes/http_transaction_handler/main.cc b/nodes/http_transaction_handler/main.cc index d8095a4..a4dd49a 100755 --- a/nodes/http_transaction_handler/main.cc +++ b/nodes/http_transaction_handler/main.cc @@ -17,6 +17,7 @@ #include "gradual_deployment.h" #include "http_manager.h" #include "layer_7_access_control.h" +#include "rate_limit.h" #include "waap.h" #include "ips_comp.h" #include "keyword_comp.h" @@ -30,6 +31,7 @@ main(int argc, char **argv) GradualDeployment, HttpManager, Layer7AccessControl, + RateLimit, WaapComponent, IPSComp, KeywordComp diff --git a/nodes/orchestration/package/open-appsec-ctl.sh b/nodes/orchestration/package/open-appsec-ctl.sh index 637570c..4492c5e 100644 --- a/nodes/orchestration/package/open-appsec-ctl.sh +++ b/nodes/orchestration/package/open-appsec-ctl.sh @@ -23,6 +23,7 @@ AI_VERBOSE=false PROFILE_SETTINGS_JSON_PATH=$cp_nano_conf_location/settings.json DEFAULT_HEALTH_CHECK_TMP_FILE_PATH="/tmp/cpnano_health_check_output.txt" +var_default_fog_address="i2-agents.cloud.ngen.checkpoint.com/" var_default_gem_fog_address="inext-agents.cloud.ngen.checkpoint.com" var_default_us_fog_address="inext-agents-us.cloud.ngen.checkpoint.com" var_default_au_fog_address="inext-agents-aus1.cloud.ngen.checkpoint.com" @@ -809,13 +810,6 @@ run_health_check() # Initials - rhc rm -rf "${rhc_health_check_tmp_file_path}" } -print_link_information() # Initials - pli -{ - echo "" - echo "For release notes and known limitations check: https://docs.openappsec.io/release-notes" - echo "For troubleshooting and support: https://openappsec.io/support" -} - should_add_color_to_status() # Initials - sacts { sacts_ps_cmd="ps aux" @@ -964,11 +958,13 @@ run_status() # Initials - rs if echo "$rs_orch_status" | grep -q "update status"; then rs_line_count=$(echo "$rs_orch_status" | grep -c '^') rs_policy_load_time="$(echo "${rs_orch_status}" | grep "Last policy update"| sed "s|\"||g" | sed "s|,||g")" + rs_ai_model_ver="$(echo "${rs_orch_status}" | grep "AI model version"| sed "s|\"||g" | sed "s|,||g")" rs_temp_old_status=$(echo "$rs_orch_status" | sed -r "${rs_line_count},${rs_line_count}d; "' 1,1d; s/^\s*//g; s/^\n//g; s/\"//g; s/\\n/\n/g; s/\,//g') else rs_temp_old_status=$(sed 's/{//g' <${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json | sed 's/}//g' | sed 's/"//g' | sed 's/,//g' | sed -r '/^\s*$/d' | sed -r 's/^ //g') rs_policy_load_time="$(cat ${FILESYSTEM_PATH}/conf/orchestration_status.json | grep "Last policy update" | sed "s|\"||g" | sed "s|,||g")" + rs_ai_model_ver="$(cat ${FILESYSTEM_PATH}/conf/orchestration_status.json | grep "AI model version" | sed "s|\"||g" | sed "s|,||g")" fi if [ -n "$(cat ${FILESYSTEM_PATH}/conf/agent_details.json | grep "hybrid_mode")" ]; then @@ -1008,6 +1004,7 @@ run_status() # Initials - rs fi echo "Policy load status: ${rs_policy_load_status}" echo ${rs_policy_load_time} + echo ${rs_ai_model_ver} echo "" for service in $all_services; do @@ -1245,7 +1242,7 @@ run_ai() # Initials - ra done if [ "$ra_upload_to_fog" = "false" ]; then - printf "Would you like to upload the file to be inspected by the product support team? [y/n] " && read -r ra_should_upload + printf "Should upload to Checkpoints' cloud? [y/n] " && read -r ra_should_upload case $ra_should_upload in [Yy] | [Yy][Ee][Ss]) ra_upload_to_fog=true ;; *) ;; @@ -1261,7 +1258,7 @@ run_ai() # Initials - ra else ra_orch_status=$(curl_func "$(extract_api_port orchestration)"/show-orchestration-status) if ! echo "$ra_orch_status" | grep -q "update status"; then - ra_orch_status=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json) + [ -f ${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestrations_status.json ] && ra_orch_status=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json) fi if [ -n "${ra_orch_status}" ]; then ra_fog_address=$(printf "%s" "$ra_orch_status" | grep "Fog address" | cut -d '"' -f4) @@ -1488,7 +1485,7 @@ set_mode() elif [ "${var_token#"$gem_prefix"}" != "${var_token}" ] || [ "${var_token#"$gem_prefix_uppercase"}" != "${var_token}" ]; then var_fog_address="$var_default_gem_fog_address" else - echo "Failed to get fog address from token: ${var_token} - check if token is legal" + var_fog_address="$var_default_fog_address" fi fog_address=$var_fog_address elif [ -z "$token" ]; then @@ -1661,7 +1658,6 @@ run() # Initials - r shift run_health_check "${@}" fi - print_link_information elif [ "--start-agent" = "$1" ] || [ "-r" = "$1" ]; then record_command $@ run_start_agent diff --git a/nodes/orchestration/package/orchestration_package.sh b/nodes/orchestration/package/orchestration_package.sh index 47e2457..b3bf746 100755 --- a/nodes/orchestration/package/orchestration_package.sh +++ b/nodes/orchestration/package/orchestration_package.sh @@ -40,6 +40,7 @@ EGG_MODE= ORCHESTRATION_CONF_FILE="${CONF_PATH}/cp-nano-orchestration-conf.json" ORCHESTRATION_DEBUG_CONF_FILE="${CONF_PATH}/cp-nano-orchestration-debug-conf.json" DEFAULT_SETTINGS_PATH="${CONF_PATH}/settings.json" +var_default_fog_address="https://i2-agents.cloud.ngen.checkpoint.com/" var_default_gem_fog_address="https://inext-agents.cloud.ngen.checkpoint.com" var_default_us_fog_address="https://inext-agents-us.cloud.ngen.checkpoint.com" var_default_au_fog_address="https://inext-agents-aus1.cloud.ngen.checkpoint.com" @@ -345,7 +346,7 @@ if [ "$RUN_MODE" = "install" ] && [ $var_offline_mode = false ]; then elif [ "${var_token#"$gem_prefix"}" != "${var_token}" ] || [ "${var_token#"$gem_prefix_uppercase"}" != "${var_token}" ]; then var_fog_address="$var_default_gem_fog_address" else - echo "Failed to get fog address from token: ${var_token} - check if token is legal" + var_fog_address="$var_default_fog_address" fi fi fi @@ -439,6 +440,28 @@ cp_copy() # Initials - cc cp_print "Destination md5, after the copy:\n$DEST_AFTER_COPY" } +update_cloudguard_appsec_manifest() +{ + if [ -z ${CLOUDGUARD_APPSEC_STANDALONE} ] || [ -z ${DOCKER_RPM_ENABLED} ]; then + return + fi + + selected_cloudguard_appsec_manifest_path="/tmp/cloudguard_appsec_manifest.json" + if [ "${DOCKER_RPM_ENABLED}" = "false" ]; then + selected_cloudguard_appsec_manifest_path="/tmp/self_managed_cloudguard_appsec_manifest.json" + fi + + if [ ! -f "$selected_cloudguard_appsec_manifest_path" ]; then + return + fi + + cloudguard_appsec_manifest_path="${selected_cloudguard_appsec_manifest_path}.used" + mv "$selected_cloudguard_appsec_manifest_path" "$cloudguard_appsec_manifest_path" + fog_host=$(echo "$var_fog_address" | sed 's/https\?:\/\///') + fog_host=${fog_host%/} + sed "s/namespace/${fog_host}/g" ${cloudguard_appsec_manifest_path} > "${FILESYSTEM_PATH}/${CONF_PATH}/manifest.json" +} + install_watchdog_gaia() { # verify that DB is clean from cp-nano-watchdog @@ -907,6 +930,8 @@ install_orchestration() cp_exec "mkdir -p ${LOG_FILE_PATH}/${LOG_PATH}" cp_exec "mkdir -p ${FILESYSTEM_PATH}/${DATA_PATH}" + update_cloudguard_appsec_manifest + if [ ! -f ${FILESYSTEM_PATH}/${DEFAULT_SETTINGS_PATH} ]; then echo "{\"agentSettings\": []}" > ${FILESYSTEM_PATH}/${DEFAULT_SETTINGS_PATH} fi