Merge pull request #57 from openappsec/Sep_24_2023-Dev

Sep 24 2023 dev
This commit is contained in:
WrightNed 2023-09-28 19:43:02 +03:00 committed by GitHub
commit a2ee6ca839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
108 changed files with 2853 additions and 546 deletions

View File

@ -104,12 +104,13 @@ Before compiling the services, you'll need to ensure the latest development vers
* GTest * GTest
* GMock * GMock
* cURL * cURL
* Hiredis
An example of installing the packages on Alpine: An example of installing the packages on Alpine:
```bash ```bash
$ apk update $ 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 ## Compiling and packaging the agent code

View File

@ -20,6 +20,9 @@
#include "environment/evaluator_templates.h" #include "environment/evaluator_templates.h"
#include "i_environment.h" #include "i_environment.h"
#include "singleton.h" #include "singleton.h"
#include "debug.h"
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
using namespace std; using namespace std;
using namespace EnvironmentHelper; using namespace EnvironmentHelper;
@ -55,6 +58,51 @@ EqualHost::evalVariable() const
return lower_host_ctx == lower_host; return lower_host_ctx == lower_host;
} }
WildcardHost::WildcardHost(const vector<string> &params)
{
if (params.size() != 1) reportWrongNumberOfParams("WildcardHost", params.size(), 1, 1);
host = params[0];
}
Maybe<bool, Context::Error>
WildcardHost::evalVariable() const
{
I_Environment *env = Singleton::Consume<I_Environment>::by<WildcardHost>();
auto host_ctx = env->get<string>(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<string> &params) EqualListeningIP::EqualListeningIP(const vector<string> &params)
{ {
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1); if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1);

View File

@ -75,6 +75,7 @@ GenericRulebase::Impl::preload()
addMatcher<IpProtocolMatcher>(); addMatcher<IpProtocolMatcher>();
addMatcher<UrlMatcher>(); addMatcher<UrlMatcher>();
addMatcher<EqualHost>(); addMatcher<EqualHost>();
addMatcher<WildcardHost>();
addMatcher<EqualListeningIP>(); addMatcher<EqualListeningIP>();
addMatcher<EqualListeningPort>(); addMatcher<EqualListeningPort>();
addMatcher<BeginWithUri>(); addMatcher<BeginWithUri>();

View File

@ -32,6 +32,19 @@ private:
std::string host; std::string host;
}; };
class WildcardHost : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
{
public:
WildcardHost(const std::vector<std::string> &params);
static std::string getName() { return "WildcardHost"; }
Maybe<bool, Context::Error> evalVariable() const override;
private:
std::string host;
};
class EqualListeningIP : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment> class EqualListeningIP : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
{ {
public: public:

View File

@ -14,13 +14,15 @@
#ifndef __I_LOCAL_POLICY_MGMT_GEN_H__ #ifndef __I_LOCAL_POLICY_MGMT_GEN_H__
#define __I_LOCAL_POLICY_MGMT_GEN_H__ #define __I_LOCAL_POLICY_MGMT_GEN_H__
#include "i_env_details.h"
class I_LocalPolicyMgmtGen class I_LocalPolicyMgmtGen
{ {
public: public:
virtual std::string parsePolicy(const std::string &policy_version) = 0; virtual std::string generateAppSecLocalPolicy(
virtual const std::string & getAgentPolicyPath(void) const = 0; EnvType env_type,
virtual const std::string & getLocalPolicyPath(void) const = 0; const std::string &policy_version,
virtual void setPolicyPath(const std::string &new_local_policy_path) = 0; const std::string &local_policy_path) = 0;
protected: protected:
~I_LocalPolicyMgmtGen() {} ~I_LocalPolicyMgmtGen() {}

View File

@ -34,6 +34,7 @@ public:
virtual const std::string & getUpdateTime() const = 0; virtual const std::string & getUpdateTime() const = 0;
virtual const std::string & getLastManifestUpdate() const = 0; virtual const std::string & getLastManifestUpdate() const = 0;
virtual const std::string & getPolicyVersion() 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 & getLastPolicyUpdate() const = 0;
virtual const std::string & getLastSettingsUpdate() const = 0; virtual const std::string & getLastSettingsUpdate() const = 0;
virtual const std::string & getUpgradeMode() const = 0; virtual const std::string & getUpgradeMode() const = 0;

View File

@ -106,8 +106,9 @@ public:
const std::string &profile_id = "") const = 0; const std::string &profile_id = "") const = 0;
virtual bool isNonEmptyFile(const std::string &path) const = 0; virtual bool isNonEmptyFile(const std::string &path) const = 0;
virtual std::shared_ptr<std::ifstream> fileStreamWrapper(const std::string &path) const = 0;
virtual Maybe<std::string> readFile(const std::string &path) const = 0; virtual Maybe<std::string> 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 removeFile(const std::string &path) const = 0;
virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0; virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0;
virtual void deleteVirtualTenantProfileFiles( virtual void deleteVirtualTenantProfileFiles(
@ -116,6 +117,7 @@ public:
const std::string &conf_path) const = 0; const std::string &conf_path) const = 0;
virtual bool copyFile(const std::string &src_path, const std::string &dst_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 bool doesFileExist(const std::string &file_path) const = 0;
virtual void getClusterId() const = 0;
virtual void fillKeyInJson( virtual void fillKeyInJson(
const std::string &filename, const std::string &filename,
const std::string &_key, const std::string &_key,

View File

@ -31,6 +31,7 @@
#include "i_environment.h" #include "i_environment.h"
#include "i_tenant_manager.h" #include "i_tenant_manager.h"
#include "i_package_handler.h" #include "i_package_handler.h"
#include "i_env_details.h"
#include "component.h" #include "component.h"
class OrchestrationComp class OrchestrationComp
@ -52,7 +53,8 @@ class OrchestrationComp
Singleton::Consume<I_ServiceController>, Singleton::Consume<I_ServiceController>,
Singleton::Consume<I_UpdateCommunication>, Singleton::Consume<I_UpdateCommunication>,
Singleton::Consume<I_Downloader>, Singleton::Consume<I_Downloader>,
Singleton::Consume<I_ManifestController> Singleton::Consume<I_ManifestController>,
Singleton::Consume<I_EnvDetails>
{ {
public: public:
OrchestrationComp(); OrchestrationComp();

View File

@ -24,6 +24,7 @@
#include "i_time_get.h" #include "i_time_get.h"
#include "i_mainloop.h" #include "i_mainloop.h"
#include "i_agent_details.h" #include "i_agent_details.h"
#include "i_details_resolver.h"
#include "customized_cereal_map.h" #include "customized_cereal_map.h"
class OrchestrationStatus class OrchestrationStatus
@ -32,6 +33,7 @@ class OrchestrationStatus
Singleton::Provide<I_OrchestrationStatus>, Singleton::Provide<I_OrchestrationStatus>,
Singleton::Consume<I_TimeGet>, Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_AgentDetails>, Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_DetailsResolver>,
Singleton::Consume<I_OrchestrationTools>, Singleton::Consume<I_OrchestrationTools>,
Singleton::Consume<I_MainLoop> Singleton::Consume<I_MainLoop>
{ {

View File

@ -20,13 +20,23 @@
#include "i_shell_cmd.h" #include "i_shell_cmd.h"
#include "i_tenant_manager.h" #include "i_tenant_manager.h"
#include "component.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 class OrchestrationTools
: :
public Component, public Component,
Singleton::Provide<I_OrchestrationTools>, Singleton::Provide<I_OrchestrationTools>,
Singleton::Consume<I_ShellCmd>, Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_TenantManager> Singleton::Consume<I_TenantManager>,
Singleton::Consume<I_EnvDetails>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_AgentDetails>
{ {
public: public:
OrchestrationTools(); OrchestrationTools();

View File

@ -111,6 +111,26 @@ public:
public: public:
UpgradeSchedule() = default; 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 init(const std::string &_upgrade_mode) { mode = _upgrade_mode; }
void void
@ -142,6 +162,22 @@ public:
C2S_LABEL_OPTIONAL_PARAM(std::vector<std::string>, days, "upgradeDay"); C2S_LABEL_OPTIONAL_PARAM(std::vector<std::string>, 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( CheckUpdateRequest(
const std::string &_manifest, const std::string &_manifest,
const std::string &_policy, const std::string &_policy,
@ -224,8 +260,10 @@ public:
void void
setUpgradeFields(const std::string &_upgrade_mode) setUpgradeFields(const std::string &_upgrade_mode)
{ {
upgrade_schedule.setActive(true); UpgradeSchedule upgrade_schedule;
upgrade_schedule.get().init(_upgrade_mode); upgrade_schedule.init(_upgrade_mode);
local_configuration_settings.setActive(true);
local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule);
} }
void void
@ -235,12 +273,14 @@ public:
const uint &_upgrade_duration_hours, const uint &_upgrade_duration_hours,
const std::vector<std::string> &_upgrade_days) const std::vector<std::string> &_upgrade_days)
{ {
upgrade_schedule.setActive(true); UpgradeSchedule upgrade_schedule;
if (!_upgrade_days.empty()) { if (!_upgrade_days.empty()) {
upgrade_schedule.get().init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days); upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days);
return; } 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: private:
@ -297,7 +337,7 @@ private:
C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type"); C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type");
C2S_LABEL_PARAM(std::string, policy_version, "policyVersion"); 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_policy, "virtualPolicy");
S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings"); S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings");

32
components/include/rate_limit.h Executable file
View File

@ -0,0 +1,32 @@
#ifndef __RATE_LIMIT_H_
#define __RATE_LIMIT_H_
#include <string>
#include "component.h"
#include "singleton.h"
#include "i_mainloop.h"
#include "i_environment.h"
class RateLimit
:
public Component,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Environment>
{
public:
RateLimit();
~RateLimit();
void preload() override;
void init() override;
void fini() override;
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __RATE_LIMIT_H_

View File

@ -0,0 +1,142 @@
#ifndef __RATE_LIMIT_CONFIG_H__
#define __RATE_LIMIT_CONFIG_H__
#include <string>
#include <vector>
#include <algorithm>
#include <cereal/archives/json.hpp>
#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<RateLimitTrigger> & 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<RateLimitTrigger> 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<RateLimitRule> & 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<std::string> 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<std::set<GenericConfigId>>(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<RateLimitRule> rate_limit_rules;
};
#endif // __RATE_LIMIT_CONFIG_H__

View File

@ -1,4 +1,6 @@
add_subdirectory(ips) add_subdirectory(ips)
add_subdirectory(layer_7_access_control) add_subdirectory(layer_7_access_control)
add_subdirectory(local_policy_mgmt_gen)
add_subdirectory(orchestration) add_subdirectory(orchestration)
add_subdirectory(rate_limit)
add_subdirectory(waap) add_subdirectory(waap)

View File

@ -74,7 +74,7 @@ public:
getCrowdsecEventId() const getCrowdsecEventId() const
{ {
if (!crowdsec_event_id) return genError("Empty ID"); 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"; } bool isMalicious() const { return type == "ban"; }
@ -280,6 +280,8 @@ Layer7AccessControl::Impl::generateLog(const string &source_ip, const Intelligen
<< LogField("sourceIP", source_ip) << LogField("sourceIP", source_ip)
<< LogField("externalVendorName", "CrowdSec") << LogField("externalVendorName", "CrowdSec")
<< LogField("waapIncidentType", "CrowdSec") << LogField("waapIncidentType", "CrowdSec")
<< LogField("practiceSubType", "Web Access Control")
<< LogField("practiceType", "Access Control")
<< ip_reputation.getCrowdsecEventId() << ip_reputation.getCrowdsecEventId()
<< ip_reputation.getType() << ip_reputation.getType()
<< ip_reputation.getOrigin() << ip_reputation.getOrigin()

View File

@ -248,7 +248,7 @@ Layer7AccessControlTest::verifyReport(
EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\"")); EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"waapIncidentType\": \"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("\"externalVendorRecommendedAction\": \"ban\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\"")); EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\""));

View File

@ -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
)

View File

@ -34,7 +34,7 @@ AppSecWebBotsURI::getURI() const
return uri; return uri;
} }
std::vector<std::string> vector<string>
AppSecPracticeAntiBot::getIjectedUris() const AppSecPracticeAntiBot::getIjectedUris() const
{ {
vector<string> injected; vector<string> injected;
@ -44,7 +44,7 @@ AppSecPracticeAntiBot::getIjectedUris() const
return injected; return injected;
} }
std::vector<std::string> vector<string>
AppSecPracticeAntiBot::getValidatedUris() const AppSecPracticeAntiBot::getValidatedUris() const
{ {
vector<string> validated; vector<string> validated;
@ -315,18 +315,74 @@ TriggersInWaapSection::save(cereal::JSONOutputArchive &out_ar) const
); );
} }
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) AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
{ {
string source_ident = parsed_trusted_sources.getSourceIdent(); string source_ident = parsed_trusted_sources.getSourceIdent();
map<string, string> behavior = {{"httpSourceId", source_ident}}; map<string, string> behavior = {{"httpSourceId", source_ident}};
parsed_behavior.push_back(behavior); parsed_behavior.push_back(behavior);
parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}}; 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<string, string> behavior = {{parsed_exceptions.getBehaviorKey(), parsed_exceptions.getBehaviorValue()}};
parsed_behavior.push_back(behavior);
}
// LCOV_EXCL_STOP
void void
AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const
{ {
string parameter_type = "TrustedSource"; if (!id.empty()) {
out_ar(cereal::make_nvp("id", id));
}
out_ar( out_ar(
cereal::make_nvp("parsedBehavior", parsed_behavior), cereal::make_nvp("parsedBehavior", parsed_behavior),
cereal::make_nvp("parsedMatch", parsed_match) cereal::make_nvp("parsedMatch", parsed_match)
@ -355,7 +411,8 @@ WebAppSection::WebAppSection(
const AppSecPracticeSpec &parsed_appsec_spec, const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger, const LogTriggerSection &parsed_log_trigger,
const string &default_mode, const string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources) const AppSecTrustedSources &parsed_trusted_sources,
const vector<InnerException> &parsed_exceptions)
: :
application_urls(_application_urls), application_urls(_application_urls),
asset_id(_asset_id), asset_id(_asset_id),
@ -382,19 +439,23 @@ WebAppSection::WebAppSection(
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) { for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident)); overrides.push_back(AppSecOverride(source_ident));
} }
for (const InnerException &exception : parsed_exceptions) {
overrides.push_back(AppSecOverride(exception));
}
} }
WebAppSection::WebAppSection( WebAppSection::WebAppSection(
const std::string &_application_urls, const string &_application_urls,
const std::string &_asset_id, const string &_asset_id,
const std::string &_asset_name, const string &_asset_name,
const std::string &_rule_id, const string &_rule_id,
const std::string &_rule_name, const string &_rule_name,
const std::string &_practice_id, const string &_practice_id,
const std::string &_practice_name, const string &_practice_name,
const string &_context, const string &_context,
const std::string &_web_attack_mitigation_severity, const string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode, const string &_web_attack_mitigation_mode,
const PracticeAdvancedConfig &_practice_advanced_config, const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots, const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger, const LogTriggerSection &parsed_log_trigger,
@ -611,7 +672,7 @@ AppsecPolicySpec::getSpecificRules() const
} }
bool bool
AppsecPolicySpec::isAssetHostExist(const std::string &full_url) const AppsecPolicySpec::isAssetHostExist(const string &full_url) const
{ {
for (const ParsedRule &rule : specific_rules) { for (const ParsedRule &rule : specific_rules) {
if (rule.getHost() == full_url) return true; if (rule.getHost() == full_url) return true;
@ -633,7 +694,7 @@ AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
parseAppsecJSONKey<vector<AppSecPracticeSpec>>("practices", practices, archive_in); parseAppsecJSONKey<vector<AppSecPracticeSpec>>("practices", practices, archive_in);
parseAppsecJSONKey<vector<AppsecTriggerSpec>>("log-triggers", log_triggers, archive_in); parseAppsecJSONKey<vector<AppsecTriggerSpec>>("log-triggers", log_triggers, archive_in);
parseAppsecJSONKey<vector<AppSecCustomResponseSpec>>("custom-responses", custom_responses, archive_in); parseAppsecJSONKey<vector<AppSecCustomResponseSpec>>("custom-responses", custom_responses, archive_in);
parseAppsecJSONKey<vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in); parseAppsecJSONKey<vector<AppsecException>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<vector<TrustedSourcesSpec>>("trusted-sources", trusted_sources, archive_in); parseAppsecJSONKey<vector<TrustedSourcesSpec>>("trusted-sources", trusted_sources, archive_in);
parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>( parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>(
"source-identifiers", "source-identifiers",
@ -666,8 +727,8 @@ AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
return custom_responses; return custom_responses;
} }
const vector<AppsecExceptionSpec> & const vector<AppsecException> &
AppsecLinuxPolicy::getAppsecExceptionSpecs() const AppsecLinuxPolicy::getAppsecExceptions() const
{ {
return exceptions; return exceptions;
} }

View File

@ -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

View File

@ -18,39 +18,61 @@ using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY); USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist // LCOV_EXCL_START Reason: no test exist
using AttributeGetter = function<vector<string>(const AppsecExceptionSpec&)>;
static const vector<pair<string, AttributeGetter>> 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<string> valid_actions = {"skip", "accept", "drop", "suppressLog"}; static const set<string> valid_actions = {"skip", "accept", "drop", "suppressLog"};
static const unordered_map<string, string> key_to_action = {
{ "accept", "accept"},
{ "drop", "reject"},
{ "skip", "ignore"},
{ "suppressLog", "ignore"}
};
void void
AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in) AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in)
{ {
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception spec"; dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception spec";
parseAppsecJSONKey<string>("name", name, archive_in); parseAppsecJSONKey<string>("action", action, archive_in, "skip");
parseAppsecJSONKey<string>("action", action, archive_in);
if (valid_actions.count(action) == 0) { if (valid_actions.count(action) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action; dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action;
} }
parseAppsecJSONKey<vector<string>>("countryCode", country_code, archive_in); parseAppsecJSONKey<vector<string>>("countryCode", country_code, archive_in);
if (!country_code.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("countryName", country_name, archive_in); parseAppsecJSONKey<vector<string>>("countryName", country_name, archive_in);
if (!country_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("hostName", host_name, archive_in); parseAppsecJSONKey<vector<string>>("hostName", host_name, archive_in);
if (!host_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramName", param_name, archive_in); parseAppsecJSONKey<vector<string>>("paramName", param_name, archive_in);
if (!param_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramValue", param_value, archive_in); parseAppsecJSONKey<vector<string>>("paramValue", param_value, archive_in);
if (!param_value.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("protectionName", protection_name, archive_in); parseAppsecJSONKey<vector<string>>("protectionName", protection_name, archive_in);
if (!protection_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIdentifier", source_identifier, archive_in); parseAppsecJSONKey<vector<string>>("sourceIdentifier", source_identifier, archive_in);
if (!source_identifier.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIp", source_ip, archive_in); parseAppsecJSONKey<vector<string>>("sourceIp", source_ip, archive_in);
if (!source_ip.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("url", url, archive_in); parseAppsecJSONKey<vector<string>>("url", url, archive_in);
} if (!url.empty()) conditions_number++;
void
AppsecExceptionSpec::setName(const string &_name)
{
name = _name;
}
const string &
AppsecExceptionSpec::getName() const
{
return name;
} }
const string & const string &
@ -113,37 +135,82 @@ AppsecExceptionSpec::getUrl() const
return url; 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<string>("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<AppsecExceptionSpec> &
AppsecException::getExceptions() const
{
return exception_spec;
}
ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception) ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
: :
match_type(MatchType::Operator), match_type(MatchType::Operator),
op("and") op("and")
{ {
if (!parsed_exception.getCountryCode().empty()) { bool single_condition = parsed_exception.isOneCondition();
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode())); 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}));
} }
if (!parsed_exception.getCountryName().empty()) { return;
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(attrib_name, exceptions_value));
items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName()));
} }
if (!parsed_exception.getParamValue().empty()) { }
items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue()));
ExceptionMatch::ExceptionMatch(const std::string &_key, const std::vector<std::string> &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}));
} }
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()));
} }
} }
@ -210,13 +277,34 @@ ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const
} }
} }
ExceptionBehavior::ExceptionBehavior( const string &
const string &_key, ExceptionMatch::getOperator() const
const string &_value)
:
key(_key),
value(_value)
{ {
return op;
}
const string &
ExceptionMatch::getKey() const
{
return key;
}
const string &
ExceptionMatch::getValue() const
{
return value[0];
}
const vector<ExceptionMatch> &
ExceptionMatch::getMatch() const
{
return items;
}
ExceptionBehavior::ExceptionBehavior(const string &_value)
{
key = _value == "suppressLog" ? "log" : "action";
value = key_to_action.at(_value);
try { try {
id = to_string(boost::uuids::random_generator()()); id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) { } catch (const boost::uuids::entropy_error &e) {
@ -234,12 +322,31 @@ ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const
); );
} }
const string const string &
ExceptionBehavior::getBehaviorId() const ExceptionBehavior::getBehaviorId() const
{ {
return id; 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 void
InnerException::save(cereal::JSONOutputArchive &out_ar) const InnerException::save(cereal::JSONOutputArchive &out_ar) const
{ {
@ -249,12 +356,30 @@ InnerException::save(cereal::JSONOutputArchive &out_ar) const
); );
} }
const string const string &
InnerException::getBehaviorId() const InnerException::getBehaviorId() const
{ {
return behavior.getBehaviorId(); 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( ExceptionsRulebase::ExceptionsRulebase(
vector<InnerException> _exceptions) vector<InnerException> _exceptions)
: :

View File

@ -202,16 +202,35 @@ private:
LogTriggerSection log; LogTriggerSection log;
}; };
class AppSecOverride class ParsedMatch
{ {
public: public:
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources); 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; void save(cereal::JSONOutputArchive &out_ar) const;
private: private:
std::string operator_type;
std::string tag;
std::string value;
std::vector<ParsedMatch> 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<std::map<std::string, std::string>> parsed_behavior; std::vector<std::map<std::string, std::string>> parsed_behavior;
std::map<std::string, std::string> parsed_match; ParsedMatch parsed_match;
}; };
class AppsecPracticeAntiBotSection class AppsecPracticeAntiBotSection
@ -254,7 +273,8 @@ public:
const AppSecPracticeSpec &parsed_appsec_spec, const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger, const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode, const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources const AppSecTrustedSources &parsed_trusted_sources,
const std::vector<InnerException> &parsed_exceptions
); );
WebAppSection( WebAppSection(
@ -430,7 +450,7 @@ public:
const std::vector<AppSecPracticeSpec> &_practices, const std::vector<AppSecPracticeSpec> &_practices,
const std::vector<AppsecTriggerSpec> &_log_triggers, const std::vector<AppsecTriggerSpec> &_log_triggers,
const std::vector<AppSecCustomResponseSpec> &_custom_responses, const std::vector<AppSecCustomResponseSpec> &_custom_responses,
const std::vector<AppsecExceptionSpec> &_exceptions, const std::vector<AppsecException> &_exceptions,
const std::vector<TrustedSourcesSpec> &_trusted_sources, const std::vector<TrustedSourcesSpec> &_trusted_sources,
const std::vector<SourceIdentifierSpecWrapper> &_sources_identifiers) const std::vector<SourceIdentifierSpecWrapper> &_sources_identifiers)
: :
@ -448,7 +468,7 @@ public:
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const; const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const; const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const;
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const; const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const;
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const; const std::vector<AppsecException> & getAppsecExceptions() const;
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const; const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const; const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
void addSpecificRule(const ParsedRule &_rule); void addSpecificRule(const ParsedRule &_rule);
@ -458,7 +478,7 @@ private:
std::vector<AppSecPracticeSpec> practices; std::vector<AppSecPracticeSpec> practices;
std::vector<AppsecTriggerSpec> log_triggers; std::vector<AppsecTriggerSpec> log_triggers;
std::vector<AppSecCustomResponseSpec> custom_responses; std::vector<AppSecCustomResponseSpec> custom_responses;
std::vector<AppsecExceptionSpec> exceptions; std::vector<AppsecException> exceptions;
std::vector<TrustedSourcesSpec> trusted_sources; std::vector<TrustedSourcesSpec> trusted_sources;
std::vector<SourceIdentifierSpecWrapper> sources_identifiers; std::vector<SourceIdentifierSpecWrapper> sources_identifiers;
}; };

View File

@ -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 <vector>
#include <map>
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#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<std::string, std::string> data;
};
#endif // __CONFIGMAPS_H__

View File

@ -31,7 +31,6 @@ class AppsecExceptionSpec
public: public:
void load(cereal::JSONInputArchive &archive_in); void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAction() const; const std::string & getAction() const;
const std::vector<std::string> & getCountryCode() const; const std::vector<std::string> & getCountryCode() const;
const std::vector<std::string> & getCountryName() const; const std::vector<std::string> & getCountryName() const;
@ -42,10 +41,10 @@ public:
const std::vector<std::string> & getSourceIdentifier() const; const std::vector<std::string> & getSourceIdentifier() const;
const std::vector<std::string> & getSourceIp() const; const std::vector<std::string> & getSourceIp() const;
const std::vector<std::string> & getUrl() const; const std::vector<std::string> & getUrl() const;
void setName(const std::string &_name); bool isOneCondition() const;
private: private:
std::string name; int conditions_number;
std::string action; std::string action;
std::vector<std::string> country_code; std::vector<std::string> country_code;
std::vector<std::string> country_name; std::vector<std::string> country_name;
@ -58,21 +57,42 @@ private:
std::vector<std::string> url; std::vector<std::string> url;
}; };
class AppsecException
{
public:
AppsecException() {};
// LCOV_EXCL_START Reason: no test exist
AppsecException(const std::string &_name, const std::vector<AppsecExceptionSpec> &_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<AppsecExceptionSpec> & getExceptions() const;
void setName(const std::string &_name);
private:
std::string name;
std::vector<AppsecExceptionSpec> exception_spec;
};
class ExceptionMatch class ExceptionMatch
{ {
public: public:
ExceptionMatch() {} ExceptionMatch() {}
ExceptionMatch(const AppsecExceptionSpec &parsed_exception); ExceptionMatch(const AppsecExceptionSpec &parsed_exception);
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value);
ExceptionMatch(const NewAppsecException &parsed_exception); ExceptionMatch(const NewAppsecException &parsed_exception);
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
:
match_type(MatchType::Condition),
key(_key),
op("in"),
value(_value)
{}
void save(cereal::JSONOutputArchive &out_ar) const; 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<ExceptionMatch> & getMatch() const;
private: private:
MatchType match_type; MatchType match_type;
@ -86,13 +106,12 @@ class ExceptionBehavior
{ {
public: public:
ExceptionBehavior() {} ExceptionBehavior() {}
ExceptionBehavior( ExceptionBehavior(const std::string &_value);
const std::string &_key,
const std::string &_value
);
void save(cereal::JSONOutputArchive &out_ar) const; void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const; const std::string & getBehaviorId() const;
const std::string & getBehaviorKey() const;
const std::string & getBehaviorValue() const;
private: private:
std::string key; std::string key;
@ -104,15 +123,13 @@ class InnerException
{ {
public: public:
InnerException() {} InnerException() {}
InnerException( InnerException(ExceptionBehavior _behavior, ExceptionMatch _match);
ExceptionBehavior _behavior,
ExceptionMatch _match)
:
behavior(_behavior),
match(_match) {}
void save(cereal::JSONOutputArchive &out_ar) const; void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const; const std::string & getBehaviorId() const;
const std::string & getBehaviorKey() const;
const std::string & getBehaviorValue() const;
const ExceptionMatch & getMatch() const;
private: private:
ExceptionBehavior behavior; ExceptionBehavior behavior;

View File

@ -47,7 +47,7 @@ public:
std::tuple<std::map<std::string, AppsecLinuxPolicy>, std::map<std::string, V1beta2AppsecLinuxPolicy>> std::tuple<std::map<std::string, AppsecLinuxPolicy>, std::map<std::string, V1beta2AppsecLinuxPolicy>>
createAppsecPoliciesFromIngresses(); createAppsecPoliciesFromIngresses();
bool getClusterId() const; void getClusterId() const;
private: private:
std::map<AnnotationKeys, std::string> parseIngressAnnotations( std::map<AnnotationKeys, std::string> parseIngressAnnotations(
@ -67,12 +67,19 @@ private:
const NewParsedRule &default_rule const NewParsedRule &default_rule
) const; ) const;
std::vector<AppsecException> extractExceptionsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
template<class T> template<class T>
std::vector<T> extractElementsFromCluster( std::vector<T> extractElementsFromCluster(
const std::string &crd_plural, const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names const std::unordered_set<std::string> &elements_names
) const; ) const;
void createSnortFile(std::vector<NewAppSecPracticeSpec> &practices) const;
template<class T> template<class T>
std::vector<T> extractV1Beta2ElementsFromCluster( std::vector<T> extractV1Beta2ElementsFromCluster(
const std::string &crd_plural, const std::string &crd_plural,

View File

@ -65,7 +65,7 @@ public:
const std::vector<AccessControlPracticeSpec> & getAccessControlPracticeSpecs() const; const std::vector<AccessControlPracticeSpec> & getAccessControlPracticeSpecs() const;
const std::vector<NewAppsecLogTrigger> & getAppsecTriggerSpecs() const; const std::vector<NewAppsecLogTrigger> & getAppsecTriggerSpecs() const;
const std::vector<NewAppSecCustomResponse> & getAppSecCustomResponseSpecs() const; const std::vector<NewAppSecCustomResponse> & getAppSecCustomResponseSpecs() const;
const std::vector<NewAppsecException> & getAppsecExceptionSpecs() const; const std::vector<NewAppsecException> & getAppsecExceptions() const;
const std::vector<NewTrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const; const std::vector<NewTrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<NewSourcesIdentifiers> & getAppsecSourceIdentifierSpecs() const; const std::vector<NewSourcesIdentifiers> & getAppsecSourceIdentifierSpecs() const;
void addSpecificRule(const NewParsedRule &_rule); void addSpecificRule(const NewParsedRule &_rule);

View File

@ -147,25 +147,25 @@ public:
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
FileSecurityProtectionsSection( FileSecurityProtectionsSection(
int file_size_limit, int _file_size_limit,
int archive_file_size_limit, int _archive_file_size_limit,
bool allow_files_without_name, bool _allow_files_without_name,
bool required_file_size_limit, bool _required_file_size_limit,
bool required_archive_extraction, bool _required_archive_extraction,
const std::string &context, const std::string &_context,
const std::string &name, const std::string &_name,
const std::string &asset_id, const std::string &_asset_id,
const std::string &practice_name, const std::string &_practice_name,
const std::string &practice_id, const std::string &_practice_id,
const std::string &action, const std::string &_action,
const std::string &files_without_name_action, const std::string &_files_without_name_action,
const std::string &high_confidence_action, const std::string &_high_confidence_action,
const std::string &medium_confidence_action, const std::string &_medium_confidence_action,
const std::string &low_confidence_action, const std::string &_low_confidence_action,
const std::string &severity_level, const std::string &_severity_level,
const std::string &fileSize_limit_action, const std::string &_file_size_limit_action,
const std::string &multi_level_archive_action, const std::string &_multi_level_archive_action,
const std::string &unopened_archive_actio const std::string &_unopened_archive_action
); );
void save(cereal::JSONOutputArchive &out_ar) const; void save(cereal::JSONOutputArchive &out_ar) const;
@ -265,6 +265,7 @@ class NewFileSecurity
public: public:
void load(cereal::JSONInputArchive &archive_in); void load(cereal::JSONInputArchive &archive_in);
const std::string & getOverrideMode() const;
const NewFileSecurityArchiveInspection & getArchiveInspection() const; const NewFileSecurityArchiveInspection & getArchiveInspection() const;
const NewFileSecurityLargeFileInspection & getLargeFileInspection() const; const NewFileSecurityLargeFileInspection & getLargeFileInspection() const;
FileSecurityProtectionsSection createFileSecurityProtectionsSection( FileSecurityProtectionsSection createFileSecurityProtectionsSection(
@ -287,17 +288,210 @@ private:
NewFileSecurityLargeFileInspection large_file_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<std::string> &_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<std::string> 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<std::string> &_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<std::string> 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<std::string> &_tags,
const std::vector<std::string> &_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<std::string> tags;
std::vector<std::string> 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<ProtectionsProtectionsSection> &_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<ProtectionsProtectionsSection> & getProtections() const;
private:
std::vector<ProtectionsProtectionsSection> 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<ProtectionsProtectionsSection> & getProtections() const;
private:
ProtectionsSection protections;
};
class SnortSection
{
public:
// LCOV_EXCL_START Reason: no test exist
SnortSection() {};
SnortSection(
const std::vector<SnortProtectionsSection> &_snort,
const std::vector<ProtectionsSection> &_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<ProtectionsSection> & getProtections() const;
private:
std::vector<SnortProtectionsSection> snort_protections;
std::vector<ProtectionsSection> protections;
};
class SnortSectionWrapper
{
public:
// LCOV_EXCL_START Reason: no test exist
SnortSectionWrapper() {};
SnortSectionWrapper(
const std::vector<SnortProtectionsSection> &_snort,
const std::vector<ProtectionsSection> &_protections)
:
snort(SnortSection(_snort, _protections))
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
SnortSection snort;
};
class NewSnortSignaturesAndOpenSchemaAPI class NewSnortSignaturesAndOpenSchemaAPI
{ {
public: public:
void load(cereal::JSONInputArchive &archive_in); void load(cereal::JSONInputArchive &archive_in);
void addFile(const std::string &file_name);
const std::string & getOverrideMode() const; const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const; const std::vector<std::string> & getConfigMap() const;
const std::vector<std::string> & getFiles() const;
private: private:
std::string override_mode; std::string override_mode;
std::vector<std::string> config_map; std::vector<std::string> config_map;
std::vector<std::string> files;
}; };
class NewAppSecWebBotsURI class NewAppSecWebBotsURI
@ -371,8 +565,8 @@ class NewAppSecPracticeSpec
public: public:
void load(cereal::JSONInputArchive &archive_in); void load(cereal::JSONInputArchive &archive_in);
NewSnortSignaturesAndOpenSchemaAPI & getSnortSignatures();
const NewSnortSignaturesAndOpenSchemaAPI & getOpenSchemaValidation() const; const NewSnortSignaturesAndOpenSchemaAPI & getOpenSchemaValidation() const;
const NewSnortSignaturesAndOpenSchemaAPI & getSnortSignatures() const;
const NewAppSecPracticeWebAttacks & getWebAttacks() const; const NewAppSecPracticeWebAttacks & getWebAttacks() const;
const NewAppSecPracticeAntiBot & getAntiBot() const; const NewAppSecPracticeAntiBot & getAntiBot() const;
const NewIntrusionPrevention & getIntrusionPrevention() const; const NewIntrusionPrevention & getIntrusionPrevention() const;

View File

@ -61,6 +61,7 @@ public:
const TriggersWrapper &_trrigers, const TriggersWrapper &_trrigers,
const RulesConfigWrapper &_rules, const RulesConfigWrapper &_rules,
const IntrusionPreventionWrapper &_ips, const IntrusionPreventionWrapper &_ips,
const SnortSectionWrapper &_snort,
const AccessControlRulebaseWrapper &_rate_limit, const AccessControlRulebaseWrapper &_rate_limit,
const FileSecurityWrapper &_file_security, const FileSecurityWrapper &_file_security,
const ExceptionsWrapper &_exceptions, const ExceptionsWrapper &_exceptions,
@ -70,6 +71,7 @@ public:
trrigers(_trrigers), trrigers(_trrigers),
rules(_rules), rules(_rules),
ips(_ips), ips(_ips),
snort(_snort),
rate_limit(_rate_limit), rate_limit(_rate_limit),
file_security(_file_security), file_security(_file_security),
exceptions(_exceptions), exceptions(_exceptions),
@ -82,6 +84,7 @@ private:
TriggersWrapper trrigers; TriggersWrapper trrigers;
RulesConfigWrapper rules; RulesConfigWrapper rules;
IntrusionPreventionWrapper ips; IntrusionPreventionWrapper ips;
SnortSectionWrapper snort;
AccessControlRulebaseWrapper rate_limit; AccessControlRulebaseWrapper rate_limit;
FileSecurityWrapper file_security; FileSecurityWrapper file_security;
ExceptionsWrapper exceptions; ExceptionsWrapper exceptions;
@ -129,7 +132,8 @@ public:
private: private:
std::string getPolicyName(const std::string &policy_path); std::string getPolicyName(const std::string &policy_path);
Maybe<AppsecLinuxPolicy> openPolicyAsJson(const std::string &policy_path); template<class T>
Maybe<T> openFileAsJson(const std::string &path);
void clearElementsMaps(); void clearElementsMaps();
@ -155,6 +159,20 @@ private:
std::map<AnnotationTypes, std::string> &rule_annotations std::map<AnnotationTypes, std::string> &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<AnnotationTypes, std::string> &rule_annotations
);
void void
createFileSecuritySections( createFileSecuritySections(
const std::string &asset_id, const std::string &asset_id,
@ -215,10 +233,12 @@ private:
std::map<std::string, LogTriggerSection> log_triggers; std::map<std::string, LogTriggerSection> log_triggers;
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers; std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
std::map<std::string, InnerException> inner_exceptions; std::map<std::string, std::vector<InnerException>> inner_exceptions;
std::map<std::string, WebAppSection> web_apps; std::map<std::string, WebAppSection> web_apps;
std::map<std::string, RulesConfigRulebase> rules_config; std::map<std::string, RulesConfigRulebase> rules_config;
std::map<std::string, IpsProtectionsSection> ips; std::map<std::string, IpsProtectionsSection> ips;
std::map<std::string, SnortProtectionsSection> snort;
std::map<std::string, ProtectionsSection> snort_protections;
std::map<std::string, FileSecurityProtectionsSection> file_security; std::map<std::string, FileSecurityProtectionsSection> file_security;
std::map<std::string, RateLimitSection> rate_limit; std::map<std::string, RateLimitSection> rate_limit;
std::map<std::string, UsersIdentifiersRulebase> users_identifiers; std::map<std::string, UsersIdentifiersRulebase> users_identifiers;

View File

@ -12,7 +12,7 @@
// limitations under the License. // limitations under the License.
#include "k8s_policy_utils.h" #include "k8s_policy_utils.h"
#include "namespace_data.h" #include "configmaps.h"
using namespace std; using namespace std;
@ -184,6 +184,36 @@ getAppSecClassNameFromCluster()
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
vector<AppsecException>
K8sPolicyUtils::extractExceptionsFromCluster(
const string &crd_plural,
const unordered_set<string> &elements_names) const
{
dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural;
vector<AppsecException> elements;
for (const string &element_name : elements_names) {
dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name;
auto maybe_appsec_element = getObjectFromCluster<AppsecSpecParser<vector<AppsecExceptionSpec>>>(
"/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<vector<AppsecExceptionSpec>> appsec_element = maybe_appsec_element.unpack();
elements.push_back(AppsecException(element_name, appsec_element.getSpec()));
}
return elements;
}
template<class T> template<class T>
vector<T> vector<T>
K8sPolicyUtils::extractElementsFromCluster( K8sPolicyUtils::extractElementsFromCluster(
@ -292,7 +322,8 @@ K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds(
policy_elements_names[AnnotationTypes::WEB_USER_RES] policy_elements_names[AnnotationTypes::WEB_USER_RES]
); );
vector<AppsecExceptionSpec> exceptions = extractElementsFromCluster<AppsecExceptionSpec>(
vector<AppsecException> exceptions = extractExceptionsFromCluster(
"exceptions", "exceptions",
policy_elements_names[AnnotationTypes::EXCEPTION] policy_elements_names[AnnotationTypes::EXCEPTION]
); );
@ -320,6 +351,34 @@ K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds(
} }
// LCOV_EXCL_START Reason: no test exist // LCOV_EXCL_START Reason: no test exist
void
K8sPolicyUtils::createSnortFile(vector<NewAppSecPracticeSpec> &practices) const
{
for (NewAppSecPracticeSpec &practice : practices) {
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<K8sPolicyUtils>();
auto path = "/etc/cp/conf/snort/snort_k8s_" + practice.getName() + ".rule";
bool append_mode = false;
for (const string &config_map : practice.getSnortSignatures().getConfigMap())
{
auto maybe_configmap = getObjectFromCluster<ConfigMaps>(
"/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<V1beta2AppsecLinuxPolicy> Maybe<V1beta2AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds( K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spec, const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spec,
@ -349,6 +408,8 @@ K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE] policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE]
); );
createSnortFile(threat_prevention_practices);
vector<AccessControlPracticeSpec> access_control_practices = vector<AccessControlPracticeSpec> access_control_practices =
extractV1Beta2ElementsFromCluster<AccessControlPracticeSpec>( extractV1Beta2ElementsFromCluster<AccessControlPracticeSpec>(
"accesscontrolpractice", "accesscontrolpractice",
@ -404,7 +465,7 @@ doesVersionExist(const map<string, string> &annotations, const string &version)
} }
return false; return false;
} }
//need to refactor don't forget that
std::tuple<Maybe<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>> std::tuple<Maybe<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const
{ {
@ -524,50 +585,3 @@ K8sPolicyUtils::createAppsecPoliciesFromIngresses()
} }
return make_tuple(v1bet1_policies, v1bet2_policies); return make_tuple(v1bet1_policies, v1bet2_policies);
} }
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";
}
bool
K8sPolicyUtils::getClusterId() const
{
string playground_uid = isPlaygroundEnv() ? "playground-" : "";
dbgTrace(D_LOCAL_POLICY) << "Getting cluster UID";
auto maybe_namespaces_data = getObjectFromCluster<NamespaceData>("/api/v1/namespaces/");
if (!maybe_namespaces_data.ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve K8S namespace data. Error: "
<< maybe_namespaces_data.getErr();
return false;
}
NamespaceData namespaces_data = maybe_namespaces_data.unpack();
Maybe<string> maybe_ns_uid = namespaces_data.getNamespaceUidByName("kube-system");
if (!maybe_ns_uid.ok()) {
dbgWarning(D_LOCAL_POLICY) << maybe_ns_uid.getErr();
return false;
}
string uid = playground_uid + maybe_ns_uid.unpack();
dbgTrace(D_LOCAL_POLICY) << "Found k8s cluster UID: " << uid;
I_Environment *env = Singleton::Consume<I_Environment>::by<K8sPolicyUtils>();
env->getConfigurationContext().registerValue<string>(
"k8sClusterId",
uid,
EnvKeyAttr::LogSection::SOURCE
);
I_AgentDetails *i_agent_details = Singleton::Consume<I_AgentDetails>::by<K8sPolicyUtils>();
i_agent_details->setClusterId(uid);
return true;
}

View File

@ -43,7 +43,7 @@
#include "include/rules_config_section.h" #include "include/rules_config_section.h"
#include "include/trusted_sources_section.h" #include "include/trusted_sources_section.h"
#include "include/policy_maker_utils.h" #include "include/policy_maker_utils.h"
#include "include/k8s_policy_utils.h" #include "k8s_policy_utils.h"
#include "i_env_details.h" #include "i_env_details.h"
using namespace std; using namespace std;
@ -64,31 +64,10 @@ public:
void void
init() init()
{ {
env_details = Singleton::Consume<I_EnvDetails>::by<LocalPolicyMgmtGenerator::Impl>();
env_type = env_details->getEnvType();
if (env_type == EnvType::LINUX) {
dbgInfo(D_LOCAL_POLICY) << "Initializing Linux policy generator";
local_policy_path = getFilesystemPathConfig() + default_local_mgmt_policy_path;
return;
}
dbgInfo(D_LOCAL_POLICY) << "Initializing K8S policy generator";
k8s_policy_utils.init();
Singleton::Consume<I_MainLoop>::by<LocalPolicyMgmtGenerator::Impl>()->addOneTimeRoutine(
I_MainLoop::RoutineType::Offline,
[this] ()
{
while(!k8s_policy_utils.getClusterId()) {
Singleton::Consume<I_MainLoop>::by<LocalPolicyMgmtGenerator::Impl>()->yield(chrono::seconds(1));
}
return;
},
"Get k8s cluster ID"
);
} }
string string
parseLinuxPolicy(const string &policy_version) parseLinuxPolicy(const string &policy_version, const string &local_policy_path)
{ {
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - embedded environment"; dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - embedded environment";
@ -104,6 +83,10 @@ public:
{ {
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment"; 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(); auto appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses();
if (!std::get<0>(appsec_policies).empty()) { if (!std::get<0>(appsec_policies).empty()) {
return policy_maker_utils.proccesMultipleAppsecPolicies<AppsecLinuxPolicy, ParsedRule>( return policy_maker_utils.proccesMultipleAppsecPolicies<AppsecLinuxPolicy, ParsedRule>(
@ -120,27 +103,14 @@ public:
} }
string string
parsePolicy(const string &policy_version) generateAppSecLocalPolicy(EnvType env_type, const string &policy_version, const string &local_policy_paths)
{ {
return isK8sEnv() ? parseK8sPolicy(policy_version) : parseLinuxPolicy(policy_version); return env_type == EnvType::K8S ?
parseK8sPolicy(policy_version) : parseLinuxPolicy(policy_version, local_policy_paths);
} }
const string & getAgentPolicyPath(void) const override { return default_local_appsec_policy_path; }
const string & getLocalPolicyPath(void) const override { return local_policy_path; }
void setPolicyPath(const string &new_local_policy_path) override { local_policy_path = new_local_policy_path; }
private: private:
bool
isK8sEnv()
{
return env_type == EnvType::K8S;
}
I_EnvDetails* env_details = nullptr;
EnvType env_type;
PolicyMakerUtils policy_maker_utils; PolicyMakerUtils policy_maker_utils;
K8sPolicyUtils k8s_policy_utils;
string local_policy_path;
}; };

View File

@ -47,7 +47,7 @@ V1beta2AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
} }
const vector<NewAppsecException> & const vector<NewAppsecException> &
V1beta2AppsecLinuxPolicy::getAppsecExceptionSpecs() const V1beta2AppsecLinuxPolicy::getAppsecExceptions() const
{ {
return exceptions; return exceptions;
} }

View File

@ -217,23 +217,253 @@ NewAppSecPracticeWebAttacks::getMode(const string &default_mode) const
return key_to_practices_val.at(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<std::string> &_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<std::string> &_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<string>("type", type, archive_in);
parseAppsecJSONKey<string>("SSM", SSM, archive_in);
parseAppsecJSONKey<string>("keywords", keywords, archive_in);
parseAppsecJSONKey<vector<string>>("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<std::string> &_tags,
const std::vector<std::string> &_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<bool>("silent", silent, archive_in);
parseAppsecJSONKey<string>("protectionName", protection_name, archive_in);
parseAppsecJSONKey<string>("severity", severity, archive_in);
parseAppsecJSONKey<string>("confidenceLevel", confidence_level, archive_in);
parseAppsecJSONKey<string>("performanceImpact", performance_impact, archive_in);
parseAppsecJSONKey<string>("lastUpdate", last_update, archive_in);
parseAppsecJSONKey<string>("maintrainId", maintrain_id, archive_in);
parseAppsecJSONKey<vector<string>>("tags", tags, archive_in);
parseAppsecJSONKey<vector<string>>("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>("protectionMetadata", protection_metadata, archive_in);
parseAppsecJSONKey<DetectionRules>("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<ProtectionsProtectionsSection> &_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<vector<ProtectionsProtectionsSection>>("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<ProtectionsProtectionsSection> &
ProtectionsSection::getProtections() const
{
return protections;
}
void
ProtectionsSectionWrapper::serialize(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Snort Section";
parseAppsecJSONKey<ProtectionsSection>("IPSSnortSigs", protections, archive_in);
}
const vector<ProtectionsProtectionsSection> &
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 void
NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in) NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in)
{ {
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice"; dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "Inactive"); parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in); parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in);
if (valid_modes.count(override_mode) == 0) { if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode; 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 & const string &
NewSnortSignaturesAndOpenSchemaAPI::getOverrideMode() const NewSnortSignaturesAndOpenSchemaAPI::getOverrideMode() const
{ {
return override_mode; return override_mode;
} }
const vector<string> &
NewSnortSignaturesAndOpenSchemaAPI::getFiles() const
{
return files;
}
const vector<string> & const vector<string> &
NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const
{ {
@ -320,7 +550,7 @@ void
NewIntrusionPrevention::load(cereal::JSONInputArchive &archive_in) NewIntrusionPrevention::load(cereal::JSONInputArchive &archive_in)
{ {
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Intrusion Prevention practice"; dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Intrusion Prevention practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "Inactive"); parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
if (valid_modes.count(override_mode) == 0) { if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Intrusion Prevention override mode invalid: " << override_mode; dbgWarning(D_LOCAL_POLICY) << "AppSec Intrusion Prevention override mode invalid: " << override_mode;
} }
@ -596,7 +826,7 @@ void
NewFileSecurity::load(cereal::JSONInputArchive &archive_in) NewFileSecurity::load(cereal::JSONInputArchive &archive_in)
{ {
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security practice"; dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "Inactive"); parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
if (valid_modes.count(override_mode) == 0) { if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec File Security override mode invalid: " << override_mode; dbgWarning(D_LOCAL_POLICY) << "AppSec File Security override mode invalid: " << override_mode;
} }
@ -633,6 +863,11 @@ NewFileSecurity::load(cereal::JSONInputArchive &archive_in)
parseAppsecJSONKey<NewFileSecurityLargeFileInspection>("largeFileInspection", large_file_inspection, archive_in); parseAppsecJSONKey<NewFileSecurityLargeFileInspection>("largeFileInspection", large_file_inspection, archive_in);
} }
const string &
NewFileSecurity::getOverrideMode() const
{
return override_mode;
}
const NewFileSecurityArchiveInspection & const NewFileSecurityArchiveInspection &
NewFileSecurity::getArchiveInspection() const NewFileSecurity::getArchiveInspection() const
@ -707,8 +942,8 @@ NewAppSecPracticeSpec::getOpenSchemaValidation() const
return openapi_schema_validation; return openapi_schema_validation;
} }
const NewSnortSignaturesAndOpenSchemaAPI & NewSnortSignaturesAndOpenSchemaAPI &
NewAppSecPracticeSpec::getSnortSignatures() const NewAppSecPracticeSpec::getSnortSignatures()
{ {
return snort_signatures; return snort_signatures;
} }

View File

@ -27,6 +27,7 @@ SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("rules", rules), cereal::make_nvp("rules", rules),
cereal::make_nvp("ips", ips), cereal::make_nvp("ips", ips),
cereal::make_nvp("exceptions", exceptions), cereal::make_nvp("exceptions", exceptions),
cereal::make_nvp("snort", snort),
cereal::make_nvp("fileSecurity", file_security), cereal::make_nvp("fileSecurity", file_security),
cereal::make_nvp("version", policy_version) cereal::make_nvp("version", policy_version)
); );
@ -53,29 +54,30 @@ PolicyMakerUtils::getPolicyName(const string &policy_path)
return policy_name; return policy_name;
} }
Maybe<AppsecLinuxPolicy> template<class T>
PolicyMakerUtils::openPolicyAsJson(const string &policy_path) Maybe<T>
PolicyMakerUtils::openFileAsJson(const string &path)
{ {
auto maybe_policy_as_json = Singleton::Consume<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput( auto maybe_file_as_json = Singleton::Consume<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput(
getFilesystemPathConfig() + "/bin/yq " + policy_path + " -o json" getFilesystemPathConfig() + "/bin/yq " + path + " -o json"
); );
if (!maybe_policy_as_json.ok()) { if (!maybe_file_as_json.ok()) {
dbgDebug(D_NGINX_POLICY) << "Could not convert policy from yaml to json"; dbgDebug(D_NGINX_POLICY) << "Could not convert policy from yaml to json";
return genError("Could not convert policy from yaml to json. Error: " + maybe_policy_as_json.getErr()); return genError("Could not convert policy from yaml to json. Error: " + maybe_file_as_json.getErr());
} }
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>(); auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>();
auto maybe_policy = i_orchestration_tools->jsonStringToObject<AppsecLinuxPolicy>( auto maybe_file = i_orchestration_tools->jsonStringToObject<T>(
maybe_policy_as_json.unpack() maybe_file_as_json.unpack()
); );
if (!maybe_policy.ok()) { if (!maybe_file.ok()) {
string error = "Policy in path: " + policy_path + " was not loaded. Error: " + maybe_policy.getErr(); string error = "Policy in path: " + path + " was not loaded. Error: " + maybe_file.getErr();
dbgDebug(D_NGINX_POLICY) << error; dbgDebug(D_NGINX_POLICY) << error;
return genError(error); return genError(error);
} }
return maybe_policy.unpack(); return maybe_file.unpack();
} }
void void
@ -86,6 +88,11 @@ PolicyMakerUtils::clearElementsMaps()
inner_exceptions.clear(); inner_exceptions.clear();
web_apps.clear(); web_apps.clear();
rules_config.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 // LCOV_EXCL_START Reason: no test exist - needed for NGINX config
@ -351,6 +358,19 @@ convertMapToVector(map<K, V> map)
return vec; return vec;
} }
vector<InnerException>
convertExceptionsMapToVector(map<string, vector<InnerException>> map)
{
vector<InnerException> 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<class T, class R> template<class T, class R>
R R
getAppsecPracticeSpec(const string &practice_annotation_name, const T &policy) getAppsecPracticeSpec(const string &practice_annotation_name, const T &policy)
@ -404,7 +424,7 @@ template<class T, class R>
R R
getAppsecExceptionSpec(const string &exception_annotation_name, const T &policy) getAppsecExceptionSpec(const string &exception_annotation_name, const T &policy)
{ {
auto exceptions_vec = policy.getAppsecExceptionSpecs(); auto exceptions_vec = policy.getAppsecExceptions();
auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name); auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name);
if (exception_it == exceptions_vec.end()) { if (exception_it == exceptions_vec.end()) {
@ -710,26 +730,24 @@ createTrustedSourcesSection<V1beta2AppsecLinuxPolicy>(
} }
template<class T> template<class T>
InnerException vector<InnerException>
createExceptionSection( createExceptionSection(
const string &exception_annotation_name, const string &exception_annotation_name,
const T &policy) const T &policy)
{ {
AppsecExceptionSpec exception_spec = AppsecException exception_spec =
getAppsecExceptionSpec<T, AppsecExceptionSpec>(exception_annotation_name, policy); getAppsecExceptionSpec<T, AppsecException>(exception_annotation_name, policy);
ExceptionMatch exception_match(exception_spec); vector<InnerException> res;
string behavior = for (auto exception : exception_spec.getExceptions()) {
exception_spec.getAction() == "skip" ? ExceptionMatch exception_match(exception);
"ignore" : ExceptionBehavior exception_behavior(exception.getAction());
exception_spec.getAction(); res.push_back(InnerException(exception_behavior, exception_match));
}
ExceptionBehavior exception_behavior("action", behavior); return res;
InnerException inner_exception(exception_behavior, exception_match);
return inner_exception;
} }
template<> template<>
InnerException vector<InnerException>
createExceptionSection<V1beta2AppsecLinuxPolicy>( createExceptionSection<V1beta2AppsecLinuxPolicy>(
const string &exception_annotation_name, const string &exception_annotation_name,
const V1beta2AppsecLinuxPolicy &policy) const V1beta2AppsecLinuxPolicy &policy)
@ -737,14 +755,9 @@ createExceptionSection<V1beta2AppsecLinuxPolicy>(
NewAppsecException exception_spec = NewAppsecException exception_spec =
getAppsecExceptionSpec<V1beta2AppsecLinuxPolicy, NewAppsecException>(exception_annotation_name, policy); getAppsecExceptionSpec<V1beta2AppsecLinuxPolicy, NewAppsecException>(exception_annotation_name, policy);
ExceptionMatch exception_match(exception_spec); ExceptionMatch exception_match(exception_spec);
string behavior = ExceptionBehavior exception_behavior(exception_spec.getAction());
exception_spec.getAction() == "skip" ?
"ignore" :
exception_spec.getAction();
ExceptionBehavior exception_behavior("action", behavior);
InnerException inner_exception(exception_behavior, exception_match); InnerException inner_exception(exception_behavior, exception_match);
return inner_exception; return {inner_exception};
} }
template<class T> template<class T>
@ -842,10 +855,13 @@ createMultiRulesSections(
const string &web_user_res_vec_type, const string &web_user_res_vec_type,
const string &asset_name, const string &asset_name,
const string &exception_name, const string &exception_name,
const string &exception_id) const vector<InnerException> &exceptions)
{ {
PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name); PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name);
ParametersSection exception_param = ParametersSection(exception_id, exception_name); vector<ParametersSection> exceptions_result;
for (auto exception : exceptions) {
exceptions_result.push_back(ParametersSection(exception.getBehaviorId(), exception_name));
}
vector<RulesTriggerSection> triggers; vector<RulesTriggerSection> triggers;
if (!log_trigger_id.empty()) { if (!log_trigger_id.empty()) {
@ -864,7 +880,7 @@ createMultiRulesSections(
url, url,
uri, uri,
{practice}, {practice},
{exception_param}, exceptions_result,
triggers triggers
); );
@ -889,9 +905,9 @@ createMultiRulesSections(
const string &web_user_res_vec_type, const string &web_user_res_vec_type,
const string &asset_name, const string &asset_name,
const string &exception_name, const string &exception_name,
const string &exception_id) const vector<InnerException> &exceptions)
{ {
ParametersSection exception_param = ParametersSection(exception_id, exception_name); ParametersSection exception_param = ParametersSection(exceptions[0].getBehaviorId(), exception_name);
vector<PracticeSection> practices; vector<PracticeSection> practices;
if (!practice_id.empty()) { if (!practice_id.empty()) {
@ -941,6 +957,9 @@ PolicyMakerUtils::createIpsSections(
auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>( auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>(
rule_annotations[AnnotationTypes::PRACTICE], rule_annotations[AnnotationTypes::PRACTICE],
policy); policy);
if (apssec_practice.getIntrusionPrevention().getMode().empty()) return;
IpsProtectionsSection ips_section = IpsProtectionsSection( IpsProtectionsSection ips_section = IpsProtectionsSection(
context, context,
asset_name, asset_name,
@ -955,6 +974,74 @@ PolicyMakerUtils::createIpsSections(
ips[asset_name] = ips_section; 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<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput(cmd);
if (!res.ok()) {
dbgWarning(D_LOCAL_POLICY) << res.getErr();
return;
}
Maybe<ProtectionsSectionWrapper> maybe_protections = openFileAsJson<ProtectionsSectionWrapper>(path + ".out");
if (!maybe_protections.ok()){
dbgWarning(D_LOCAL_POLICY) << maybe_protections.getErr();
return;
}
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>();
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<AnnotationTypes, string> &rule_annotations)
{
auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>(
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 void
PolicyMakerUtils::createFileSecuritySections( PolicyMakerUtils::createFileSecuritySections(
const string &asset_id, const string &asset_id,
@ -968,6 +1055,9 @@ PolicyMakerUtils::createFileSecuritySections(
auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>( auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>(
rule_annotations[AnnotationTypes::PRACTICE], rule_annotations[AnnotationTypes::PRACTICE],
policy); policy);
if (apssec_practice.getFileSecurity().getOverrideMode().empty()) return;
auto file_security_section = apssec_practice.getFileSecurity().createFileSecurityProtectionsSection( auto file_security_section = apssec_practice.getFileSecurity().createFileSecurityProtectionsSection(
context, context,
asset_name, asset_name,
@ -1095,7 +1185,7 @@ PolicyMakerUtils::createThreatPreventionPracticeSections(
"WebUserResponse", "WebUserResponse",
asset_name, asset_name,
rule_annotations[AnnotationTypes::EXCEPTION], rule_annotations[AnnotationTypes::EXCEPTION],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId() inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
); );
rules_config[rule_config.getAssetName()] = rule_config; rules_config[rule_config.getAssetName()] = rule_config;
@ -1121,6 +1211,17 @@ PolicyMakerUtils::createThreatPreventionPracticeSections(
rule_annotations rule_annotations
); );
createSnortSections(
"practiceId(" + practice_id + ")",
rule_config.getAssetName(),
rule_config.getAssetId(),
rule_annotations[AnnotationTypes::PRACTICE],
practice_id,
current_identifier,
policy,
rule_annotations
);
createFileSecuritySections( createFileSecuritySections(
rule_config.getAssetId(), rule_config.getAssetId(),
rule_config.getAssetName(), rule_config.getAssetName(),
@ -1158,12 +1259,13 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
) )
); );
ExceptionsWrapper exceptions_section({ ExceptionsWrapper exceptions_section({
ExceptionsRulebase(convertMapToVector(inner_exceptions)) ExceptionsRulebase(convertExceptionsMapToVector(inner_exceptions))
}); });
AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {})); AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {}));
RulesConfigWrapper rules_config_section(convertMapToVector(rules_config), convertMapToVector(users_identifiers)); RulesConfigWrapper rules_config_section(convertMapToVector(rules_config), convertMapToVector(users_identifiers));
IntrusionPreventionWrapper ips_section(convertMapToVector(ips)); IntrusionPreventionWrapper ips_section(convertMapToVector(ips));
SnortSectionWrapper snort_section(convertMapToVector(snort), convertMapToVector(snort_protections));
FileSecurityWrapper file_security_section(convertMapToVector(file_security)); FileSecurityWrapper file_security_section(convertMapToVector(file_security));
AccessControlRulebaseWrapper rate_limit_section(convertMapToVector(rate_limit)); AccessControlRulebaseWrapper rate_limit_section(convertMapToVector(rate_limit));
SecurityAppsWrapper security_app_section = SecurityAppsWrapper( SecurityAppsWrapper security_app_section = SecurityAppsWrapper(
@ -1171,6 +1273,7 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
triggers_section, triggers_section,
rules_config_section, rules_config_section,
ips_section, ips_section,
snort_section,
rate_limit_section, rate_limit_section,
file_security_section, file_security_section,
exceptions_section, exceptions_section,
@ -1277,7 +1380,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
"WebUserResponse", "WebUserResponse",
full_url, full_url,
rule_annotations[AnnotationTypes::EXCEPTION], rule_annotations[AnnotationTypes::EXCEPTION],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId() inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
); );
rules_config[rule_config.getAssetName()] = rule_config; rules_config[rule_config.getAssetName()] = rule_config;
@ -1303,7 +1406,8 @@ PolicyMakerUtils::createPolicyElementsByRule(
getAppsecPracticeSpec<T, AppSecPracticeSpec>(rule_annotations[AnnotationTypes::PRACTICE], policy), getAppsecPracticeSpec<T, AppSecPracticeSpec>(rule_annotations[AnnotationTypes::PRACTICE], policy),
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
rule.getMode(), rule.getMode(),
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
); );
web_apps[rule_config.getAssetName()] = web_app; web_apps[rule_config.getAssetName()] = web_app;
} }
@ -1468,7 +1572,7 @@ PolicyMakerUtils::proccesSingleAppsecPolicy(
const string &policy_version, const string &policy_version,
const string &local_appsec_policy_path) const string &local_appsec_policy_path)
{ {
Maybe<AppsecLinuxPolicy> maybe_policy = openPolicyAsJson(policy_path); Maybe<AppsecLinuxPolicy> maybe_policy = openFileAsJson<AppsecLinuxPolicy>(policy_path);
if (!maybe_policy.ok()){ if (!maybe_policy.ok()){
dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr(); dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr();
return ""; return "";

View File

@ -98,6 +98,7 @@ PracticeSection::save(cereal::JSONOutputArchive &out_ar) const
); );
} }
// LCOV_EXCL_START Reason: no test exist
ParametersSection::ParametersSection( ParametersSection::ParametersSection(
const string &_id, const string &_id,
const string &_name) const string &_name)
@ -120,6 +121,7 @@ ParametersSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("parameterType", type) cereal::make_nvp("parameterType", type)
); );
} }
// LCOV_EXCL_STOP
RulesTriggerSection::RulesTriggerSection( RulesTriggerSection::RulesTriggerSection(
const string &_name, const string &_name,

View File

@ -12,7 +12,6 @@ add_subdirectory(manifest_controller)
add_subdirectory(update_communication) add_subdirectory(update_communication)
add_subdirectory(details_resolver) add_subdirectory(details_resolver)
add_subdirectory(health_check) add_subdirectory(health_check)
add_subdirectory(local_policy_mgmt_gen)
add_subdirectory(env_details) add_subdirectory(env_details)
#add_subdirectory(orchestration_ut) #add_subdirectory(orchestration_ut)

View File

@ -42,6 +42,16 @@ checkSamlPortal(const string &command_output)
return genError("Current host does not have SAML Portal configured"); return genError("Current host does not have SAML Portal configured");
} }
Maybe<string>
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<string> Maybe<string>
checkIDP(shared_ptr<istream> file_stream) checkIDP(shared_ptr<istream> file_stream)
{ {
@ -226,58 +236,24 @@ getSmbGWIPSecVPNBlade(const string &command_output)
{ {
return getSmbBlade(command_output, "IPSec VPN Blade was not found"); return getSmbBlade(command_output, "IPSec VPN Blade was not found");
} }
Maybe<string>
getMgmtParentObjAttr(shared_ptr<istream> 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 #endif // gaia || smb
#if defined(gaia) #if defined(gaia)
Maybe<string> Maybe<string>
getMgmtParentObjUid(shared_ptr<istream> file_stream) getMgmtParentObjUid(const string &command_output)
{ {
auto maybe_unparsed_uid = getMgmtParentObjAttr(file_stream, "cluster_object", "Uid "); return getAttr(command_output, "Parent object uuid was not found");
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;
} }
Maybe<string> Maybe<string>
getMgmtParentObjName(shared_ptr<istream> file_stream) getMgmtParentObjName(const string &command_output)
{ {
auto maybe_unparsed_name = getMgmtParentObjAttr(file_stream, "cluster_object", "Name "); return getAttr(command_output, "Parent object name was not found");
if (!maybe_unparsed_name.ok()) {
return maybe_unparsed_name;
}
const string &unparsed_name = maybe_unparsed_name.unpack();
return chopHeadAndTail(unparsed_name, "(", ")");
} }
#elif defined(smb) #elif defined(smb)
Maybe<string> Maybe<string>
getMgmtParentObjUid(const string &command_output) getSmbMgmtParentObjUid(const string &command_output)
{ {
if (!command_output.empty()) { if (!command_output.empty()) {
return command_output; return command_output;
@ -286,7 +262,7 @@ getMgmtParentObjUid(const string &command_output)
} }
Maybe<string> Maybe<string>
getMgmtParentObjName(const string &command_output) getSmbMgmtParentObjName(const string &command_output)
{ {
if (!command_output.empty()) { if (!command_output.empty()) {
return command_output; return command_output;
@ -314,6 +290,34 @@ getOsRelease(shared_ptr<istream> file_stream)
return genError("Os release was not found"); return genError("Os release was not found");
} }
Maybe<string>
getWaapModelVersion(shared_ptr<istream> 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) #if defined(alpine)
string & string &
ltrim(string &s) ltrim(string &s)

View File

@ -55,6 +55,19 @@ SHELL_CMD_HANDLER(
#if defined(gaia) #if defined(gaia)
SHELL_CMD_HANDLER("hasSupportedBlade", "enabled_blades", checkHasSupportedBlade) SHELL_CMD_HANDLER("hasSupportedBlade", "enabled_blades", checkHasSupportedBlade)
SHELL_CMD_HANDLER("hasSamlPortal", "mpclient status saml-vpn", checkSamlPortal) 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( SHELL_CMD_HANDLER(
"Hardware", "Hardware",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1", "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( SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectName", "cpProductIntegrationMgmtParentObjectName",
"cpsdwan get_data | jq -r .cluster_name", "cpsdwan get_data | jq -r .cluster_name",
getMgmtParentObjName getSmbMgmtParentObjName
) )
SHELL_CMD_HANDLER( SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectUid", "cpProductIntegrationMgmtParentObjectUid",
"cpsdwan get_data | jq -r .cluster_uuid", "cpsdwan get_data | jq -r .cluster_uuid",
getMgmtParentObjUid getSmbMgmtParentObjUid
) )
SHELL_CMD_HANDLER( SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtObjectName", "cpProductIntegrationMgmtObjectName",
@ -143,4 +156,6 @@ FILE_CONTENT_HANDLER(
FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease) FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease)
#endif // gaia || smb #endif // gaia || smb
FILE_CONTENT_HANDLER("AppSecModelVersion", "/etc/cp/conf/waap/waap.data", getWaapModelVersion)
#endif // FILE_CONTENT_HANDLER #endif // FILE_CONTENT_HANDLER

View File

@ -22,6 +22,7 @@
#include "maybe_res.h" #include "maybe_res.h"
#include "enum_array.h" #include "enum_array.h"
#include "i_shell_cmd.h" #include "i_shell_cmd.h"
#include "i_orchestration_tools.h"
#include "config.h" #include "config.h"
using namespace std; using namespace std;
@ -77,7 +78,8 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
const string &path = file_handler.second.first; const string &path = file_handler.second.first;
FileContentHandler handler = file_handler.second.second; FileContentHandler handler = file_handler.second.second;
shared_ptr<ifstream> in_file = make_shared<ifstream>(path); shared_ptr<ifstream> in_file =
Singleton::Consume<I_OrchestrationTools>::by<DetailsResolvingHanlder>()->fileStreamWrapper(path);
if (!in_file->is_open()) { if (!in_file->is_open()) {
dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path; dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
continue; continue;

View File

@ -18,11 +18,13 @@
#include <map> #include <map>
#include "i_shell_cmd.h" #include "i_shell_cmd.h"
#include "i_orchestration_tools.h"
#include "i_agent_details_reporter.h" #include "i_agent_details_reporter.h"
class DetailsResolvingHanlder class DetailsResolvingHanlder
: :
Singleton::Consume<I_ShellCmd>, Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_OrchestrationTools>,
Singleton::Consume<I_AgentDetailsReporter> Singleton::Consume<I_AgentDetailsReporter>
{ {
public: public:

View File

@ -278,6 +278,36 @@ HttpsCurl::HttpsCurl(const HttpsCurl &other) :
HttpCurl(other), HttpCurl(other),
ca_path(other.ca_path) {} 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 void
HttpsCurl::setCurlOpts(long timeout, HTTP_VERSION http_version) 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); curl_easy_setopt(curl_handle, CURLOPT_HTTP_VERSION, http_version);
//SSL options //SSL options
if (getProfileAgentSettingWithDefault<bool>( if (
false, getProfileAgentSettingWithDefault<bool>(false, "agent.config.message.ignoreSslValidation") == false
"agent.config.message.ignoreSslValidation") == false) )
{ {
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_verify_certificate); curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_verify_certificate);

View File

@ -105,6 +105,7 @@ public:
static CURLcode ssl_ctx_verify_certificate(CURL *curl, void *ssl_ctx, void *opq); static CURLcode ssl_ctx_verify_certificate(CURL *curl, void *ssl_ctx, void *opq);
static int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx); 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; void setCurlOpts(long timeout = 60L, HTTP_VERSION http_version = HTTP_VERSION::HTTP_VERSION_1_1) override;
bool downloadOpenAppsecPackages();
private: private:
std::string ca_path; std::string ca_path;

View File

@ -51,7 +51,7 @@ TEST_F(DownloaderTest, downloadFileFromFog)
calculateChecksum(Package::ChecksumTypes::SHA256, "/tmp/virtualSettings.download") calculateChecksum(Package::ChecksumTypes::SHA256, "/tmp/virtualSettings.download")
).WillOnce(Return(string("123"))); ).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)); .WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, isNonEmptyFile("/tmp/virtualSettings.download")).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_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)); .WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, isNonEmptyFile("/tmp/manifest.download")).WillOnce(Return(false)); 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_communication, downloadAttributeFile(resourse_file)).WillOnce(Return(fog_response));
EXPECT_CALL(mock_orchestration_tools, writeFile(tenant_0000_file, "/tmp/virtualPolicy_0000_profile_1234.download")) EXPECT_CALL(
.WillOnce(Return(true)); 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, fillKeyInJson(_, _, _)).WillRepeatedly(Return());
EXPECT_CALL(mock_orchestration_tools, writeFile(tenant_1111_file, "/tmp/virtualPolicy_1111_profile_1235.download")) EXPECT_CALL(
.WillOnce(Return(true)); mock_orchestration_tools,
writeFile(
tenant_1111_file,
"/tmp/virtualPolicy_1111_profile_1235.download",
false)
).WillOnce(Return(true));
map<pair<string, string>, string> expected_downloaded_files = map<pair<string, string>, string> expected_downloaded_files =
{ {
@ -427,7 +437,8 @@ TEST_F(DownloaderTest, download_virtual_settings)
mock_orchestration_tools, mock_orchestration_tools,
writeFile( writeFile(
tenant_0000_file, tenant_0000_file,
tenant_0000_path.str() tenant_0000_path.str(),
false
) )
).WillOnce(Return(true)); ).WillOnce(Return(true));

View File

@ -37,8 +37,8 @@ private:
std::string loadCAChainDir(); std::string loadCAChainDir();
Maybe<void> getFileSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token); Maybe<void> getFileSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
Maybe<void> getFileHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token); Maybe<void> getFileHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token);
Maybe<void> curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
Maybe<void> curlGetFileOverHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token); Maybe<void> curlGetFileOverHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token);
Maybe<void> curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
}; };
// LCOV_EXCL_STOP // LCOV_EXCL_STOP

View File

@ -592,8 +592,13 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s
proxy_config->getProxyCredentials(ProxyProtocol::HTTPS), proxy_config->getProxyCredentials(ProxyProtocol::HTTPS),
cert_file_path); cert_file_path);
bool connection_ok;
if (url.getBaseURL().unpack() == "downloads.openappsec.io") {
connection_ok = ssl_curl_client.downloadOpenAppsecPackages();
} else {
ssl_curl_client.setCurlOpts(); ssl_curl_client.setCurlOpts();
bool connection_ok = ssl_curl_client.connect(); connection_ok = ssl_curl_client.connect();
}
if (!connection_ok) if (!connection_ok)
{ {
stringstream url_s; stringstream url_s;

View File

@ -21,6 +21,7 @@
#include "config.h" #include "config.h"
#include "log_generator.h" #include "log_generator.h"
#include "health_check_manager.h" #include "health_check_manager.h"
#include "agent_core_utilities.h"
using namespace std; using namespace std;
using namespace ReportIS; using namespace ReportIS;
@ -145,9 +146,11 @@ private:
initCloudVendorConfig() initCloudVendorConfig()
{ {
static const map<string, pair<string, int>> ip_port_defaults_map = { static const map<string, pair<string, int>> ip_port_defaults_map = {
{"Azure", make_pair("168.63.129.16", 8117)}, {"Azure", make_pair(getenv("DOCKER_RPM_ENABLED") ? "" : "168.63.129.16", 8117)},
{"Aws", make_pair("", 8117)} {"Aws", make_pair("", 8117)},
{"Local", make_pair("", 8117)}
}; };
auto cloud_vendor_maybe = getSetting<string>("reverseProxy", "cloudVendorName"); auto cloud_vendor_maybe = getSetting<string>("reverseProxy", "cloudVendorName");
if (cloud_vendor_maybe.ok()) { if (cloud_vendor_maybe.ok()) {
const string cloud_vendor = cloud_vendor_maybe.unpack(); 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<I_ShellCmd>::by<HealthChecker>()->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 bool
nginxContainerIsRunning() nginxContainerIsRunning()
{ {
static const string nginx_container_name = "cp_nginx_gaia"; static const string nginx_container_name = "cp_nginx_gaia";
static const string cmd_running = static const string cmd_running =
"docker ps --filter name=" + nginx_container_name + " --filter status=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<I_ShellCmd>::by<HealthChecker>()->getExecOutput(cmd_running); auto maybe_result = Singleton::Consume<I_ShellCmd>::by<HealthChecker>()->getExecOutput(cmd_running);
if (!maybe_result.ok()) { if (!maybe_result.ok()) {
@ -263,7 +289,6 @@ private:
} }
return (*maybe_result).find(nginx_container_name) != string::npos; return (*maybe_result).find(nginx_container_name) != string::npos;
} }
void void
@ -279,7 +304,7 @@ private:
{ {
if (open_connections_counter >= max_connections) { if (open_connections_counter >= max_connections) {
dbgDebug(D_HEALTH_CHECK) 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 << open_connections_counter
<< "maximum allowed: " << "maximum allowed: "
<< max_connections; << max_connections;
@ -331,6 +356,42 @@ private:
"health check failed\r\n"; "health check failed\r\n";
static const vector<char> failure_response_buffer(failure_response.begin(), failure_response.end()); static const vector<char> 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<char> 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()) { if (nginxContainerIsRunning()) {
dbgDebug(D_HEALTH_CHECK) dbgDebug(D_HEALTH_CHECK)
<< "nginx conatiner is running, returning the following response: " << "nginx conatiner is running, returning the following response: "

View File

@ -194,7 +194,7 @@ TEST_F(HealthCheckerTest, connectionsLimit)
connection_handler_routine(); connection_handler_routine();
EXPECT_THAT( 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")
); );
} }

View File

@ -31,6 +31,14 @@ class ApplyPolicyEvent : public Event<ApplyPolicyEvent>
{ {
public: public:
ApplyPolicyEvent() {} 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 class DeclarativePolicyUtils
@ -40,6 +48,7 @@ class DeclarativePolicyUtils
Singleton::Consume<I_EnvDetails>, Singleton::Consume<I_EnvDetails>,
Singleton::Consume<I_AgentDetails>, Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_OrchestrationTools>, Singleton::Consume<I_OrchestrationTools>,
public Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_RestApi>, Singleton::Consume<I_RestApi>,
public Listener<ApplyPolicyEvent> public Listener<ApplyPolicyEvent>
{ {
@ -50,8 +59,7 @@ public:
void void
doCall() override doCall() override
{ {
Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->setPolicyPath(policy_path.get()); ApplyPolicyEvent(policy_path.get()).notify();
ApplyPolicyEvent().notify();
} }
private: private:
@ -80,6 +88,7 @@ public:
private: private:
std::string getCleanChecksum(const std::string &unclean_checksum); std::string getCleanChecksum(const std::string &unclean_checksum);
std::string local_policy_path;
std::string curr_version; std::string curr_version;
std::string curr_policy; std::string curr_policy;
bool should_apply_policy; bool should_apply_policy;

View File

@ -142,6 +142,7 @@ protected:
std::string base64Encode(const std::string &in) const; std::string base64Encode(const std::string &in) const;
std::string buildBasicAuthHeader(const std::string &username, const std::string &pass) const; std::string buildBasicAuthHeader(const std::string &username, const std::string &pass) const;
std::string buildOAuth2Header(const std::string &token) const; std::string buildOAuth2Header(const std::string &token) const;
std::string getUserEdition() const;
// This apps which the orchestrations requires them from Fog. // This apps which the orchestrations requires them from Fog.
std::vector<std::string> required_security_apps; std::vector<std::string> required_security_apps;

View File

@ -54,6 +54,7 @@ public:
last_update = i_orch_status->getUpdateTime(); last_update = i_orch_status->getUpdateTime();
last_update_status = i_orch_status->getUpdateStatus(); last_update_status = i_orch_status->getUpdateStatus();
policy_version = i_orch_status->getPolicyVersion(); policy_version = i_orch_status->getPolicyVersion();
waap_model_version = i_orch_status->getWaapModelVersion();
last_policy_update = i_orch_status->getLastPolicyUpdate(); last_policy_update = i_orch_status->getLastPolicyUpdate();
last_manifest_update = i_orch_status->getLastManifestUpdate(); last_manifest_update = i_orch_status->getLastManifestUpdate();
last_settings_update = i_orch_status->getLastSettingsUpdate(); 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, "Last update");
S2C_LABEL_PARAM(std::string, last_update_status, "Last update status"); 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, 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_policy_update, "Last policy update");
S2C_LABEL_PARAM(std::string, last_manifest_update, "Last manifest update"); S2C_LABEL_PARAM(std::string, last_manifest_update, "Last manifest update");
S2C_LABEL_PARAM(std::string, last_settings_update, "Last settings update"); S2C_LABEL_PARAM(std::string, last_settings_update, "Last settings update");

View File

@ -45,6 +45,7 @@ public:
MOCK_CONST_METHOD0(getUpdateTime, const std::string&()); MOCK_CONST_METHOD0(getUpdateTime, const std::string&());
MOCK_CONST_METHOD0(getLastManifestUpdate, const std::string&()); MOCK_CONST_METHOD0(getLastManifestUpdate, const std::string&());
MOCK_CONST_METHOD0(getPolicyVersion, 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(getLastPolicyUpdate, const std::string&());
MOCK_CONST_METHOD0(getLastSettingsUpdate, const std::string&()); MOCK_CONST_METHOD0(getLastSettingsUpdate, const std::string&());
MOCK_CONST_METHOD0(getUpgradeMode, const std::string&()); MOCK_CONST_METHOD0(getUpgradeMode, const std::string&());

View File

@ -1,3 +0,0 @@
include_directories(include)
add_library(local_policy_mgmt_gen appsec_practice_section.cc exceptions_section.cc ingress_data.cc local_policy_mgmt_gen.cc policy_maker_utils.cc rules_config_section.cc settings_section.cc snort_section.cc triggers_section.cc trusted_sources_section.cc k8s_policy_utils.cc namespace_data.cc new_appsec_linux_policy.cc new_appsec_policy_crd_parser.cc new_custom_response.cc new_exceptions.cc new_log_trigger.cc new_practice.cc new_trusted_sources.cc access_control_practice.cc)

View File

@ -1,106 +0,0 @@
// 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_COMMON_H__
#define __K8S_POLICY_COMMON_H__
#include <map>
#include <set>
#include <string>
#include <cereal/archives/json.hpp>
#include "config.h"
#include "debug.h"
#include "rest.h"
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
enum class PracticeType { WebApplication, WebAPI };
enum class TriggerType { Log, WebUserResponse };
enum class MatchType { Condition, Operator };
static const std::unordered_map<std::string, MatchType> string_to_match_type = {
{ "condition", MatchType::Condition },
{ "operator", MatchType::Operator }
};
static const std::unordered_map<std::string, PracticeType> string_to_practice_type = {
{ "WebApplication", PracticeType::WebApplication },
{ "WebAPI", PracticeType::WebAPI }
};
static const std::unordered_map<std::string, TriggerType> string_to_trigger_type = {
{ "log", TriggerType::Log },
{ "WebUserResponse", TriggerType::WebUserResponse }
};
static const std::unordered_map<std::string, std::string> key_to_practices_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
template <typename T>
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();
}
}
template <typename T>
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));
} catch (cereal::Exception &e) {
dbgError(D_LOCAL_POLICY) << "Failed to load spec JSON. Error: " << e.what();
return false;
}
return true;
}
const T & getSpec() const { return spec; }
private:
T spec;
};
// LCOV_EXCL_STOP
#endif // __K8S_POLICY_COMMON_H__

View File

@ -76,6 +76,7 @@ public:
private: private:
bool changeManifestFile(const string &new_manifest_file); bool changeManifestFile(const string &new_manifest_file);
bool updateIgnoreListForNSaaS();
bool bool
handlePackage( handlePackage(
@ -155,12 +156,36 @@ ManifestController::Impl::init()
} }
} }
bool
ManifestController::Impl::updateIgnoreListForNSaaS()
{
if (!getProfileAgentSettingWithDefault<bool>(false, "accessControl.isAwsNSaaS")) return false;
auto ignore_packages_path = getConfigurationWithDefault<string>(
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 bool
ManifestController::Impl::updateManifest(const string &new_manifest_file) ManifestController::Impl::updateManifest(const string &new_manifest_file)
{ {
auto i_env = Singleton::Consume<I_Environment>::by<ManifestController>(); auto i_env = Singleton::Consume<I_Environment>::by<ManifestController>();
auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF); auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF);
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestController>(); auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestController>();
static bool ignore_packages_update = false;
if (isIgnoreFile(new_manifest_file)) { if (isIgnoreFile(new_manifest_file)) {
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) { 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"; dbgDebug(D_ORCHESTRATOR) << "Starting to update manifest file";
auto ignored_settings_packages = getProfileAgentSetting<IgnoredPackages>("orchestration.IgnoredPackagesList"); auto ignored_settings_packages = getProfileAgentSetting<IgnoredPackages>("orchestration.IgnoredPackagesList");
set<string> packages_to_ignore = ignore_packages; set<string> 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)"; dbgTrace(D_ORCHESTRATOR) << "Nothing to update (\"ignore all\" turned on)";
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) { 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) { if (all_installed && (any_installed || no_change) && no_corrupted_package) {
manifest_file_update = changeManifestFile(new_manifest_file); manifest_file_update = changeManifestFile(new_manifest_file);
// In NSaaS - set ignore packages to any
ignore_packages_update = updateIgnoreListForNSaaS();
} else if (any_installed) { } else if (any_installed) {
manifest_file_update = orchestration_tools->packagesToJsonFile(current_packages, manifest_file_path); manifest_file_update = orchestration_tools->packagesToJsonFile(current_packages, manifest_file_path);
} }

View File

@ -11,6 +11,7 @@
#include "mock/mock_time_get.h" #include "mock/mock_time_get.h"
#include "mock/mock_orchestration_tools.h" #include "mock/mock_orchestration_tools.h"
#include "mock/mock_agent_details.h" #include "mock/mock_agent_details.h"
#include "mock/mock_details_resolver.h"
#include "mock/mock_mainloop.h" #include "mock/mock_mainloop.h"
#include "mock/mock_rest_api.h" #include "mock/mock_rest_api.h"
@ -38,9 +39,17 @@ public:
.WillOnce(DoAll(SaveArg<2>(&routine), Return(1)) .WillOnce(DoAll(SaveArg<2>(&routine), Return(1))
); );
EXPECT_CALL(mock_tools, readFile(file_path)).WillOnce(Return(start_file_content)); EXPECT_CALL(mock_tools, readFile(file_path)).WillOnce(Return(start_file_content));
prepareResolvedDetails();
orchestration_status.init(); orchestration_status.init();
} }
void
prepareResolvedDetails()
{
map<string, string> resolved_details({{"AppSecModelVersion", waap_model}});
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_details));
}
string string
orchestrationStatusFileToString() orchestrationStatusFileToString()
{ {
@ -82,7 +91,8 @@ public:
const string &registration_details_architecture = "", const string &registration_details_architecture = "",
const string &agent_id = "None", const string &agent_id = "None",
const string &profile_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" return "{\n"
@ -91,6 +101,7 @@ public:
" \"Last update\": \"" + last_update + "\",\n" " \"Last update\": \"" + last_update + "\",\n"
" \"Last manifest update\": \"" + last_manifest_update + "\",\n" " \"Last manifest update\": \"" + last_manifest_update + "\",\n"
" \"Policy version\": \"" + policy_version + "\",\n" " \"Policy version\": \"" + policy_version + "\",\n"
" \"AI model version\": \"" + waap_model_version + "\",\n"
" \"Last policy update\": \"" + last_policy_update + "\",\n" " \"Last policy update\": \"" + last_policy_update + "\",\n"
" \"Last settings update\": \"" + last_settings_update + "\",\n" " \"Last settings update\": \"" + last_settings_update + "\",\n"
" \"Upgrade mode\": \"" + upgrade_mode + "\",\n" " \"Upgrade mode\": \"" + upgrade_mode + "\",\n"
@ -118,12 +129,14 @@ public:
ostringstream capture_debug; ostringstream capture_debug;
StrictMock<MockOrchestrationTools> mock_tools; StrictMock<MockOrchestrationTools> mock_tools;
StrictMock<MockAgentDetails> mock_agent_details; StrictMock<MockAgentDetails> mock_agent_details;
StrictMock<MockDetailsResolver> mock_details_resolver;
OrchestrationStatus orchestration_status; OrchestrationStatus orchestration_status;
I_OrchestrationStatus * i_orchestration_status = I_OrchestrationStatus * i_orchestration_status =
Singleton::Consume<I_OrchestrationStatus>::from(orchestration_status); Singleton::Consume<I_OrchestrationStatus>::from(orchestration_status);
string file_path; string file_path;
Maybe<string> start_file_content = genError("No file"); Maybe<string> start_file_content = genError("No file");
I_MainLoop::Routine routine; I_MainLoop::Routine routine;
string waap_model = "Advanced model";
}; };
TEST_F(OrchestrationStatusTest, doNothing) TEST_F(OrchestrationStatusTest, doNothing)
@ -147,6 +160,7 @@ TEST_F(OrchestrationStatusTest, recoverFields)
TEST_F(OrchestrationStatusTest, loadFromFile) TEST_F(OrchestrationStatusTest, loadFromFile)
{ {
prepareResolvedDetails();
Maybe<string> status = genError("No file");; Maybe<string> status = genError("No file");;
CPTestTempfile status_file; CPTestTempfile status_file;
file_path = status_file.fname; file_path = status_file.fname;
@ -214,12 +228,14 @@ TEST_F(OrchestrationStatusTest, recoveryFields)
const string agent_id = "AgentId"; const string agent_id = "AgentId";
const string profile_id = "ProfileId"; const string profile_id = "ProfileId";
const string tenant_id = "TenantId"; const string tenant_id = "TenantId";
auto fog_addr = Maybe<string>(string("FogDomain")); auto fog_addr = Maybe<string>(string("FogDomain"));
EXPECT_CALL(mock_agent_details, getAgentId()).WillOnce(Return(agent_id)); 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, getProfileId()).WillOnce(Return(profile_id));
EXPECT_CALL(mock_agent_details, getTenantId()).WillOnce(Return(tenant_id)); EXPECT_CALL(mock_agent_details, getTenantId()).WillOnce(Return(tenant_id));
EXPECT_CALL(mock_agent_details, getFogDomain()).WillOnce(Return(fog_addr)); EXPECT_CALL(mock_agent_details, getFogDomain()).WillOnce(Return(fog_addr));
i_orchestration_status->writeStatusToFile(); i_orchestration_status->writeStatusToFile();
EXPECT_THAT(capture_debug.str(), HasSubstr("Repairing status fields")); 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->getProfileId(), profile_id);
EXPECT_EQ(i_orchestration_status->getTenantId(), tenant_id); EXPECT_EQ(i_orchestration_status->getTenantId(), tenant_id);
EXPECT_EQ(i_orchestration_status->getFogAddress(), fog_addr.unpack()); EXPECT_EQ(i_orchestration_status->getFogAddress(), fog_addr.unpack());
EXPECT_EQ(i_orchestration_status->getWaapModelVersion(), waap_model);
} }
TEST_F(OrchestrationStatusTest, updateAllLastUpdatesTypes) TEST_F(OrchestrationStatusTest, updateAllLastUpdatesTypes)
@ -419,6 +436,7 @@ TEST_F(OrchestrationStatusTest, setAllFields)
" \"Last update\": \"current time\",\n" " \"Last update\": \"current time\",\n"
" \"Last manifest update\": \"current time\",\n" " \"Last manifest update\": \"current time\",\n"
" \"Policy version\": \"12\",\n" " \"Policy version\": \"12\",\n"
" \"AI model version\": \"Advanced model\",\n"
" \"Last policy update\": \"current time\",\n" " \"Last policy update\": \"current time\",\n"
" \"Last settings update\": \"current time\",\n" " \"Last settings update\": \"current time\",\n"
" \"Upgrade mode\": \"Test Mode\",\n" " \"Upgrade mode\": \"Test Mode\",\n"

View File

@ -108,6 +108,7 @@ public:
last_update_attempt = from.last_update_attempt; last_update_attempt = from.last_update_attempt;
last_manifest_update = from.last_manifest_update; last_manifest_update = from.last_manifest_update;
policy_version = from.policy_version; policy_version = from.policy_version;
waap_model_version = from.waap_model_version;
last_policy_update = from.last_policy_update; last_policy_update = from.last_policy_update;
last_settings_update = from.last_settings_update; last_settings_update = from.last_settings_update;
upgrade_mode = from.upgrade_mode; upgrade_mode = from.upgrade_mode;
@ -128,6 +129,7 @@ public:
const string & getUpdateTime() const { return last_update_time; } const string & getUpdateTime() const { return last_update_time; }
const string & getLastManifestUpdate() const { return last_manifest_update; } const string & getLastManifestUpdate() const { return last_manifest_update; }
const string & getPolicyVersion() const { return policy_version; } 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 & getLastPolicyUpdate() const { return last_policy_update; }
const string & getLastSettingsUpdate() const { return last_settings_update; } const string & getLastSettingsUpdate() const { return last_settings_update; }
const string & getUpgradeMode() const { return upgrade_mode; } const string & getUpgradeMode() const { return upgrade_mode; }
@ -142,6 +144,16 @@ public:
const map<string, string> & getServicePolicies() const { return service_policies; } const map<string, string> & getServicePolicies() const { return service_policies; }
const map<string, string> & getServiceSettings() const { return service_settings; } const map<string, string> & getServiceSettings() const { return service_settings; }
void updateWaapModelVersion() {
map<string, string> details_resolver =
Singleton::Consume<I_DetailsResolver>::by<OrchestrationStatus>()->getResolvedDetails();
if (details_resolver.find("AppSecModelVersion") != details_resolver.end()) {
waap_model_version = details_resolver["AppSecModelVersion"];
} else {
waap_model_version = "None";
}
}
void void
insertServicePolicy(const string &key, const string &value) insertServicePolicy(const string &key, const string &value)
{ {
@ -267,12 +279,13 @@ public:
last_manifest_update = "None"; last_manifest_update = "None";
last_policy_update = "None"; last_policy_update = "None";
last_settings_update = "None"; last_settings_update = "None";
waap_model_version = "None";
fog_address = "None"; fog_address = "None";
agent_id = "None"; agent_id = "None";
profile_id = "None"; profile_id = "None";
tenant_id = "None"; tenant_id = "None";
registration_status = "None"; registration_status = "None";
manifest_status = "None"; manifest_status = getenv("CLOUDGUARD_APPSEC_STANDALONE") ? "Succeeded" : "None";
upgrade_mode = "None"; upgrade_mode = "None";
} }
@ -292,6 +305,7 @@ public:
} else { } else {
fog_address = "None"; fog_address = "None";
} }
updateWaapModelVersion();
} }
} }
@ -304,6 +318,7 @@ public:
archive(cereal::make_nvp("Last update", last_update_time)); archive(cereal::make_nvp("Last update", last_update_time));
archive(cereal::make_nvp("Last manifest update", last_manifest_update)); archive(cereal::make_nvp("Last manifest update", last_manifest_update));
archive(cereal::make_nvp("Policy version", policy_version)); 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 policy update", last_policy_update));
archive(cereal::make_nvp("Last settings update", last_settings_update)); archive(cereal::make_nvp("Last settings update", last_settings_update));
archive(cereal::make_nvp("Upgrade mode", upgrade_mode)); archive(cereal::make_nvp("Upgrade mode", upgrade_mode));
@ -331,6 +346,7 @@ public:
archive.setNextName(nullptr); 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 policy update", last_policy_update));
archive(cereal::make_nvp("Last settings update", last_settings_update)); archive(cereal::make_nvp("Last settings update", last_settings_update));
@ -368,6 +384,7 @@ private:
string last_update_attempt; string last_update_attempt;
string last_manifest_update; string last_manifest_update;
string policy_version; string policy_version;
string waap_model_version;
string last_policy_update; string last_policy_update;
string last_settings_update; string last_settings_update;
string upgrade_mode; string upgrade_mode;
@ -387,13 +404,14 @@ class OrchestrationStatus::Impl : Singleton::Provide<I_OrchestrationStatus>::Fro
{ {
public: public:
void void
writeStatusToFile() writeStatusToFile() override
{ {
auto orchestration_status_path = getConfigurationWithDefault<string>( auto orchestration_status_path = getConfigurationWithDefault<string>(
filesystem_prefix + "/conf/orchestration_status.json", filesystem_prefix + "/conf/orchestration_status.json",
"orchestration", "orchestration",
"Orchestration status path" "Orchestration status path"
); );
status.updateWaapModelVersion();
auto write_result = auto write_result =
orchestration_tools->objectToJsonFile<Status>(status, orchestration_status_path); orchestration_tools->objectToJsonFile<Status>(status, orchestration_status_path);
if (!write_result) { if (!write_result) {
@ -497,6 +515,7 @@ private:
const string & getUpdateTime() const override { return status.getUpdateTime(); } const string & getUpdateTime() const override { return status.getUpdateTime(); }
const string & getLastManifestUpdate() const override { return status.getLastManifestUpdate(); } const string & getLastManifestUpdate() const override { return status.getLastManifestUpdate(); }
const string & getPolicyVersion() const override { return status.getPolicyVersion(); } 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 & getLastPolicyUpdate() const override { return status.getLastPolicyUpdate(); }
const string & getLastSettingsUpdate() const override { return status.getLastSettingsUpdate(); } const string & getLastSettingsUpdate() const override { return status.getLastSettingsUpdate(); }
const string & getUpgradeMode() const override { return status.getUpgradeMode(); } const string & getUpgradeMode() const override { return status.getUpgradeMode(); }

View File

@ -189,6 +189,10 @@ public:
"Orchestration runner", "Orchestration runner",
true true
); );
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
orchestration_tools->getClusterId();
hybrid_mode_metric.init( hybrid_mode_metric.init(
"Watchdog Metrics", "Watchdog Metrics",
ReportIS::AudienceTeam::AGENT_CORE, ReportIS::AudienceTeam::AGENT_CORE,
@ -198,7 +202,6 @@ public:
ReportIS::Audience::INTERNAL ReportIS::Audience::INTERNAL
); );
hybrid_mode_metric.registerListener(); hybrid_mode_metric.registerListener();
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
orchestration_tools->loadTenantsFromDir( orchestration_tools->loadTenantsFromDir(
getConfigurationWithDefault<string>(getFilesystemPathConfig() + "/conf/", "orchestration", "Conf dir") getConfigurationWithDefault<string>(getFilesystemPathConfig() + "/conf/", "orchestration", "Conf dir")
); );
@ -1485,6 +1488,9 @@ private:
if (i_details_resolver->compareCheckpointVersion(8100, greater_equal<int>())) { if (i_details_resolver->compareCheckpointVersion(8100, greater_equal<int>())) {
agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true"); agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true");
} }
if (i_details_resolver->compareCheckpointVersion(8200, greater_equal<int>())) {
agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER82", "true");
}
#endif // gaia || smb #endif // gaia || smb
if (agent_data_report == curr_agent_data_report) { if (agent_data_report == curr_agent_data_report) {

View File

@ -1,5 +1,5 @@
ADD_DEFINITIONS(-Wno-deprecated-declarations) 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) #add_subdirectory(orchestration_tools_ut)

View File

@ -12,11 +12,31 @@
// limitations under the License. // limitations under the License.
#include "namespace_data.h" #include "namespace_data.h"
#include "local_policy_common.h"
using namespace std; using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY); USE_DEBUG_FLAG(D_ORCHESTRATOR);
template <typename T>
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 class NamespaceMetadata
{ {
@ -24,9 +44,9 @@ public:
void void
load(cereal::JSONInputArchive &archive_in) load(cereal::JSONInputArchive &archive_in)
{ {
dbgFlow(D_LOCAL_POLICY); dbgFlow(D_ORCHESTRATOR);
parseAppsecJSONKey<string>("name", name, archive_in); parseNameSpaceJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("uid", uid, archive_in); parseNameSpaceJSONKey<string>("uid", uid, archive_in);
} }
const string & const string &
@ -52,7 +72,7 @@ public:
void void
load(cereal::JSONInputArchive &archive_in) load(cereal::JSONInputArchive &archive_in)
{ {
parseAppsecJSONKey<NamespaceMetadata>("metadata", metadata, archive_in); parseNameSpaceJSONKey<NamespaceMetadata>("metadata", metadata, archive_in);
} }
const NamespaceMetadata & const NamespaceMetadata &
@ -68,7 +88,7 @@ private:
bool bool
NamespaceData::loadJson(const string &json) NamespaceData::loadJson(const string &json)
{ {
dbgFlow(D_LOCAL_POLICY); dbgFlow(D_ORCHESTRATOR);
string modified_json = json; string modified_json = json;
modified_json.pop_back(); modified_json.pop_back();
stringstream in; stringstream in;
@ -81,7 +101,7 @@ NamespaceData::loadJson(const string &json)
ns_name_to_uid[single_ns_data.getMetadata().getName()] = single_ns_data.getMetadata().getUID(); ns_name_to_uid[single_ns_data.getMetadata().getName()] = single_ns_data.getMetadata().getUID();
} }
} catch (cereal::Exception &e) { } catch (cereal::Exception &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to load namespace data JSON. Error: " << e.what(); dbgWarning(D_ORCHESTRATOR) << "Failed to load namespace data JSON. Error: " << e.what();
return false; return false;
} }
return true; return true;

View File

@ -19,6 +19,7 @@
#include "cereal/types/vector.hpp" #include "cereal/types/vector.hpp"
#include "cereal/types/set.hpp" #include "cereal/types/set.hpp"
#include "agent_core_utilities.h" #include "agent_core_utilities.h"
#include "namespace_data.h"
#include <netdb.h> #include <netdb.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -47,11 +48,13 @@ public:
const string &tenant_id, const string &tenant_id,
const string &profile_id) const override; const string &profile_id) const override;
shared_ptr<ifstream> fileStreamWrapper(const std::string &path) const override;
Maybe<string> readFile(const string &path) const override; Maybe<string> 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 removeFile(const string &path) const override;
bool copyFile(const string &src_path, const string &dst_path) const override; bool copyFile(const string &src_path, const string &dst_path) const override;
bool doesFileExist(const string &file_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; void fillKeyInJson(const string &filename, const string &_key, const string &_val) const override;
bool createDirectory(const string &directory_path) const override; bool createDirectory(const string &directory_path) const override;
bool doesDirectoryExist(const string &dir_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 // 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<NamespaceData, string>
getNamespaceDataFromCluster(const string &path)
{
NamespaceData name_space;
string token = Singleton::Consume<I_EnvDetails>::by<OrchestrationTools>()->getToken();
Flags<MessageConnConfig> conn_flags;
conn_flags.setFlag(MessageConnConfig::SECURE_CONN);
conn_flags.setFlag(MessageConnConfig::IGNORE_SSL_VALIDATION);
auto messaging = Singleton::Consume<I_Messaging>::by<OrchestrationTools>();
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<string> 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<I_Environment>::by<OrchestrationTools>();
env->getConfigurationContext().registerValue<string>(
"k8sClusterId",
uid,
EnvKeyAttr::LogSection::SOURCE
);
I_AgentDetails *i_agent_details = Singleton::Consume<I_AgentDetails>::by<OrchestrationTools>();
i_agent_details->setClusterId(uid);
return true;
}
void
OrchestrationTools::Impl::getClusterId() const
{
auto env_type = Singleton::Consume<I_EnvDetails>::by<OrchestrationTools>()->getEnvType();
if (env_type == EnvType::K8S) {
Singleton::Consume<I_MainLoop>::by<OrchestrationTools>()->addOneTimeRoutine(
I_MainLoop::RoutineType::Offline,
[this] ()
{
while(!doesClusterIdExists()) {
Singleton::Consume<I_MainLoop>::by<OrchestrationTools>()->yield(chrono::seconds(1));
}
return;
},
"Get k8s cluster ID"
);
}
}
bool bool
OrchestrationTools::Impl::doesFileExist(const string &file_path) const OrchestrationTools::Impl::doesFileExist(const string &file_path) const
{ {
@ -140,7 +235,7 @@ OrchestrationTools::Impl::doesDirectoryExist(const string &dir_path) const
} }
bool 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; dbgDebug(D_ORCHESTRATOR) << "Writing file: text = " << text << ", path = " << path;
if (path.find('/') != string::npos) { if (path.find('/') != string::npos) {
@ -151,8 +246,15 @@ OrchestrationTools::Impl::writeFile(const string &text, const string &path) cons
return false; return false;
} }
} }
ofstream fout;
if (append_mode) {
fout.open(path, std::ios::app);
} else {
fout.open(path);
}
try { try {
ofstream fout(path);
fout << text; fout << text;
return true; return true;
} catch (const ofstream::failure &e) { } catch (const ofstream::failure &e) {
@ -186,6 +288,12 @@ OrchestrationTools::Impl::isNonEmptyFile(const string &path) const
return false; return false;
} }
shared_ptr<ifstream>
OrchestrationTools::Impl::fileStreamWrapper(const std::string &path) const
{
return make_shared<ifstream>(path);
}
Maybe<string> Maybe<string>
OrchestrationTools::Impl::readFile(const string &path) const OrchestrationTools::Impl::readFile(const string &path) const
{ {

View File

@ -1,8 +1,13 @@
#include "orchestration_tools.h" #include "orchestration_tools.h"
#include "cptest.h" #include "cptest.h"
#include "config_component.h"
#include "mock/mock_tenant_manager.h" #include "mock/mock_tenant_manager.h"
#include "mock/mock_shell_cmd.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 std;
using namespace testing; 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 void
cleanSpaces(string &str) cleanSpaces(string &str)
{ {
@ -47,27 +63,74 @@ public:
OrchestrationTools orchestration_tools; OrchestrationTools orchestration_tools;
I_OrchestrationTools *i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::from(orchestration_tools); I_OrchestrationTools *i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::from(orchestration_tools);
StrictMock<MockTenantManager> mock_tenant_manager; NiceMock<MockMessaging> mock_messaging;
NiceMock<MockAgentDetails> mock_agent_details;
NiceMock<MockMainLoop> mock_mainloop;
StrictMock<MockShellCmd> mock_shell_cmd; StrictMock<MockShellCmd> mock_shell_cmd;
StrictMock<EnvDetailsMocker> mock_env_details;
StrictMock<MockTenantManager> mock_tenant_manager;
::Environment env;
}; };
TEST_F(OrchestrationToolsTest, doNothing) 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<string>(namespaces)));
i_orchestration_tools->getClusterId();
routine();
}
TEST_F(OrchestrationToolsTest, writeReadTextToFile) 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->doesFileExist(manifest_file));
EXPECT_TRUE(i_orchestration_tools->isNonEmptyFile(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_EQ(manifest_text, i_orchestration_tools->readFile(manifest_file).unpack());
EXPECT_FALSE(i_orchestration_tools->isNonEmptyFile("no_such_file")); 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) 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"; string file_name = "in_test.json";
Maybe<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson(file_name); Maybe<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson(file_name);
EXPECT_FALSE(packages.ok()); EXPECT_FALSE(packages.ok());
@ -83,7 +146,7 @@ TEST_F(OrchestrationToolsTest, loadPackagesFromJsonTest)
TEST_F(OrchestrationToolsTest, copyFile) 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_TRUE(i_orchestration_tools->copyFile("in_test.json", "cpy_test.json"));
EXPECT_EQ("blabla", i_orchestration_tools->readFile("cpy_test.json").unpack()); EXPECT_EQ("blabla", i_orchestration_tools->readFile("cpy_test.json").unpack());
EXPECT_FALSE(i_orchestration_tools->copyFile("NOT_EXISTS_FILE", "cpy2_test.json")); 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<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson("packages_tmp.json"); Maybe<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson("packages_tmp.json");
EXPECT_TRUE(packages.ok()); EXPECT_TRUE(packages.ok());
EXPECT_TRUE(packages.unpack().find("nano-agent") != packages.unpack().end()); 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<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson("packages.json"); Maybe<map<string, Package>> packages = i_orchestration_tools->loadPackagesFromJson("packages.json");
EXPECT_TRUE(packages.ok()); EXPECT_TRUE(packages.ok());
EXPECT_TRUE(i_orchestration_tools->packagesToJsonFile(packages.unpack(), "packages.json")); 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)); EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path));
string settings_file_path = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; 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(), settings_file_path, false);
i_orchestration_tools->writeFile(string_stream.str(), policy_file_path); 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(settings_file_path));
EXPECT_TRUE(i_orchestration_tools->doesFileExist(policy_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)); EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path2));
string settings_file_path1 = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; 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"; 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"; 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"; 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_path1));
EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path2)); EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path2));

View File

@ -62,6 +62,8 @@ public:
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true) addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true)
).WillOnce(DoAll(SaveArg<1>(&routine), Return(1))); ).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", _, _)) EXPECT_CALL(mock_shell_cmd, getExecOutput("openssl version -d | cut -d\" \" -f2 | cut -d\"\\\"\" -f2", _, _))
.WillOnce(Return(string("OpenSSL certificates Directory"))); .WillOnce(Return(string("OpenSSL certificates Directory")));
@ -91,11 +93,11 @@ public:
Maybe<string> err = genError("No file exist"); Maybe<string> 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, 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)); 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)); 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)); Return(true));
} }

View File

@ -54,6 +54,8 @@ public:
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true) addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Orchestration runner", true)
).WillOnce(DoAll(SaveArg<1>(&routine), Return(1))); ).WillOnce(DoAll(SaveArg<1>(&routine), Return(1)));
EXPECT_CALL(mock_orchestration_tools, getClusterId());
EXPECT_CALL( EXPECT_CALL(
mock_shell_cmd, mock_shell_cmd,
getExecOutput("openssl version -d | cut -d\" \" -f2 | cut -d\"\\\"\" -f2", _, _) getExecOutput("openssl version -d | cut -d\" \" -f2 | cut -d\"\\\"\" -f2", _, _)
@ -118,11 +120,11 @@ public:
Maybe<string> err = genError("No file exist"); Maybe<string> 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, 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)); 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)); 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)); Return(true));
} }
@ -1333,26 +1335,6 @@ TEST_F(OrchestrationTest, manifestUpdate)
} catch (const invalid_argument& e) {} } 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) TEST_F(OrchestrationTest, getBadPolicyUpdate)
{ {
EXPECT_CALL( EXPECT_CALL(
@ -1815,6 +1797,7 @@ TEST_F(OrchestrationTest, GetRestOrchStatus)
" \"Last update\": \"" + test_str + "\",\n" " \"Last update\": \"" + test_str + "\",\n"
" \"Last update status\": \"" + test_str + "\",\n" " \"Last update status\": \"" + test_str + "\",\n"
" \"Policy version\": \"" + test_str + "\",\n" " \"Policy version\": \"" + test_str + "\",\n"
" \"AI model version\": \"" + test_str + "\",\n"
" \"Last policy update\": \"" + test_str + "\",\n" " \"Last policy update\": \"" + test_str + "\",\n"
" \"Last manifest update\": \"" + test_str + "\",\n" " \"Last manifest update\": \"" + test_str + "\",\n"
" \"Last settings 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, getUpdateTime()).WillOnce(ReturnRef(test_str));
EXPECT_CALL(mock_status, getLastManifestUpdate()).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, 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, getLastPolicyUpdate()).WillOnce(ReturnRef(test_str));
EXPECT_CALL(mock_status, getLastSettingsUpdate()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getLastSettingsUpdate()).WillOnce(ReturnRef(test_str));
EXPECT_CALL(mock_status, getUpgradeMode()).WillOnce(ReturnRef(test_str)); EXPECT_CALL(mock_status, getUpgradeMode()).WillOnce(ReturnRef(test_str));

View File

@ -246,7 +246,8 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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(l4_firewall, l4_firewall_policy_path, false))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
@ -357,8 +358,9 @@ TEST_F(ServiceControllerTest, supportVersions)
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_versions_path)).WillOnce(Return(false)); 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, 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))
EXPECT_CALL(mock_orchestration_tools, writeFile(versions, policy_versions_path)).WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, writeFile(versions, policy_versions_path, false)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("versions", policy_versions_path, OrchestrationStatusConfigType::POLICY)); setServiceConfiguration("versions", policy_versions_path, OrchestrationStatusConfigType::POLICY));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
@ -455,7 +457,8 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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(l4_firewall, l4_firewall_policy_path, false))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); 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, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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(l4_firewall, l4_firewall_policy_path, false))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); 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, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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(l4_firewall, l4_firewall_policy_path, false))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
@ -965,7 +970,7 @@ TEST_F(ServiceControllerTest, backup)
).WillOnce(Return(true)); ).WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
mock_orchestration_tools, 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)) EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -1078,7 +1083,7 @@ TEST_F(ServiceControllerTest, backup_file_doesnt_exist)
).WillOnce(Return(true)); ).WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
mock_orchestration_tools, 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 // backup file doesn't exist so the copyFile function should be called 0 times
@ -1194,7 +1199,7 @@ TEST_F(ServiceControllerTest, backupAttempts)
EXPECT_CALL( EXPECT_CALL(
mock_orchestration_tools, 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)) 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, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("orchestration", orchestration_policy_path, OrchestrationStatusConfigType::POLICY)); 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(l4_firewall, l4_firewall_policy_path, false))
EXPECT_CALL(mock_orchestration_tools, writeFile(orchestration, orchestration_policy_path)).WillOnce(Return(true)); .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)) EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).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, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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(
l4_firewall,
l4_firewall_policy_path,
false)).WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
mock_orchestration_status, mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY) setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)
@ -1667,7 +1679,7 @@ TEST_F(ServiceControllerTest, errorWhileWrtingNewConfiguration)
EXPECT_CALL( EXPECT_CALL(
mock_orchestration_tools, 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()); 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, 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)); .WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, setServiceConfiguration( EXPECT_CALL(mock_orchestration_status, setServiceConfiguration(
@ -1889,7 +1901,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf)
EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return)); .WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_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)). EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path, false)).
WillOnce(Return(true)); WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status, EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));

View File

@ -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) #add_subdirectory(update_communication_ut)

View File

@ -16,6 +16,7 @@ USE_DEBUG_FLAG(D_ORCHESTRATOR);
void void
DeclarativePolicyUtils::init() DeclarativePolicyUtils::init()
{ {
local_policy_path = getFilesystemPathConfig() + "/conf/local_policy.yaml";
should_apply_policy = true; should_apply_policy = true;
Singleton::Consume<I_RestApi>::by<DeclarativePolicyUtils>()->addRestCall<ApplyPolicyRest>( Singleton::Consume<I_RestApi>::by<DeclarativePolicyUtils>()->addRestCall<ApplyPolicyRest>(
RestAction::SET, "apply-policy" RestAction::SET, "apply-policy"
@ -25,9 +26,10 @@ DeclarativePolicyUtils::init()
// LCOV_EXCL_START Reason: no test exist // LCOV_EXCL_START Reason: no test exist
void void
DeclarativePolicyUtils::upon(const ApplyPolicyEvent &) DeclarativePolicyUtils::upon(const ApplyPolicyEvent &event)
{ {
dbgTrace(D_ORCHESTRATOR) << "Apply policy event"; dbgTrace(D_ORCHESTRATOR) << "Apply policy event";
local_policy_path = event.getPolicyPath();
should_apply_policy = true; should_apply_policy = true;
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -54,11 +56,9 @@ DeclarativePolicyUtils::getLocalPolicyChecksum()
return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger"); return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger");
} }
string policy_path = Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->getLocalPolicyPath();
Maybe<string> file_checksum = orchestration_tools->calculateChecksum( Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE, I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
policy_path local_policy_path
); );
if (!file_checksum.ok()) { if (!file_checksum.ok()) {
@ -83,8 +83,11 @@ void
DeclarativePolicyUtils::updateCurrentPolicy(const string &policy_checksum) DeclarativePolicyUtils::updateCurrentPolicy(const string &policy_checksum)
{ {
string clean_policy_checksum = getCleanChecksum(policy_checksum); string clean_policy_checksum = getCleanChecksum(policy_checksum);
curr_policy = Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->parsePolicy( auto env = Singleton::Consume<I_EnvDetails>::by<DeclarativePolicyUtils>()->getEnvType();
clean_policy_checksum curr_policy = Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->generateAppSecLocalPolicy(
env,
clean_policy_checksum,
local_policy_path
); );
} }
@ -94,7 +97,7 @@ DeclarativePolicyUtils::getPolicyChecksum()
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<DeclarativePolicyUtils>(); I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<DeclarativePolicyUtils>();
Maybe<string> file_checksum = orchestration_tools->calculateChecksum( Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE, I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->getAgentPolicyPath() "/tmp/local_appsec.policy"
); );
if (!file_checksum.ok()) { if (!file_checksum.ok()) {

View File

@ -187,6 +187,8 @@ FogAuthenticator::registerAgent(
request << make_pair("managedMode", "management"); request << make_pair("managedMode", "management");
} }
request << make_pair("userEdition", getUserEdition());
if (details_resolver->isReverseProxy()) { if (details_resolver->isReverseProxy()) {
request << make_pair("reverse_proxy", "true"); request << make_pair("reverse_proxy", "true");
} }
@ -207,6 +209,9 @@ FogAuthenticator::registerAgent(
if (details_resolver->compareCheckpointVersion(8100, std::greater_equal<int>())) { if (details_resolver->compareCheckpointVersion(8100, std::greater_equal<int>())) {
request << make_pair("isCheckpointVersionGER81", "true"); request << make_pair("isCheckpointVersionGER81", "true");
} }
if (details_resolver->compareCheckpointVersion(8200, std::greater_equal<int>())) {
request << make_pair("isCheckpointVersionGER82", "true");
}
#endif // gaia || smb #endif // gaia || smb
auto fog_messaging = Singleton::Consume<I_Messaging>::by<FogAuthenticator>(); auto fog_messaging = Singleton::Consume<I_Messaging>::by<FogAuthenticator>();

View File

@ -0,0 +1,9 @@
#include "fog_authenticator.h"
#include <string>
std::string
FogAuthenticator::getUserEdition() const
{
return "community";
}

View File

@ -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)

View File

@ -0,0 +1,535 @@
#include "rate_limit.h"
#include <memory>
#include <string>
#include <vector>
#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 <iostream>
#include <unordered_map>
#include <string>
#include <chrono>
#include <ctime>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <arpa/inet.h>
#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<HttpRequestHeaderEvent>
{
public:
Impl() = default;
~Impl() = default;
Maybe<string>
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<RateLimitRule>
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<GenericConfigId>(AssetMatcher::ctx_key, site_config->get_AssetId());
auto maybe_rate_limit_config = getConfiguration<RateLimitConfig>("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<string> rule_set;
Maybe<RateLimitRule> 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<I_Environment>::by<RateLimit>()->get<string>(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<float>(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<I_Environment>::by<RateLimit>()->get<string>(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<redisReply*>(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<string> rate_limit_triggers_set;
for (const auto &trigger : rule.getRateLimitTriggers()) {
rate_limit_triggers_set.insert(trigger.getTriggerId());
}
ScopedContext ctx;
ctx.registerValue<std::set<GenericConfigId>>(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<BasicRuleConfig>("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<I_Environment>::by<RateLimit>()->get<string>(HttpTransactionData::method_ctx);
if (http_method.ok()) log << LogField("httpMethod", http_method.unpack());
auto http_host =
Singleton::Consume<I_Environment>::by<RateLimit>()->get<string>(HttpTransactionData::host_name_ctx);
if (http_host.ok()) log << LogField("httpHostName", http_host.unpack());
auto source_ip =
Singleton::Consume<I_Environment>::by<RateLimit>()->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (source_ip.ok()) log << LogField("sourceIP", ipAddrToStr(source_ip.unpack()));
auto proxy_ip =
Singleton::Consume<I_Environment>::by<RateLimit>()->get<std::string>(HttpTransactionData::proxy_ip_ctx);
if (proxy_ip.ok() && source_ip.ok() && ipAddrToStr(source_ip.unpack()) != proxy_ip.unpack()) {
log << LogField("proxyIP", static_cast<std::string>(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<void>
connectRedis()
{
disconnectRedis();
redisOptions options;
memset(&options, 0, sizeof(redisOptions));
REDIS_OPTIONS_SET_TCP(
&options,
"127.0.0.1",
getConfigurationWithDefault<int>(6379, "connection", "Redis Port")
);
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = getConfigurationWithDefault<int>(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<redisReply*>(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>();
}
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<I_MainLoop>::by<RateLimit>()->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<I_MainLoop>::by<RateLimit>()->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<Impl>()) {}
RateLimit::~RateLimit() = default;
void
RateLimit::preload()
{
registerExpectedConfiguration<WaapConfigApplication>("WAAP", "WebApplicationSecurity");
registerExpectedConfiguration<WaapConfigAPI>("WAAP", "WebAPISecurity");
registerExpectedConfigFile("waap", Config::ConfigFileType::Policy);
registerExpectedConfiguration<RateLimitConfig>("rulebase", "rateLimit");
registerExpectedConfigFile("accessControlV2", Config::ConfigFileType::Policy);
registerConfigPrepareCb([]() { RateLimitConfig::resetIsActive(); });
}
void
RateLimit::init() { pimpl->init(); }
void
RateLimit::fini() { pimpl->fini(); }

View File

@ -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 <sourceIdentifier> zone=<location>_<id>:10m rate=<limit>r/<scope>;
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;
}

View File

@ -52,6 +52,7 @@ public:
virtual const std::string& get_RuleName() const = 0; virtual const std::string& get_RuleName() const = 0;
virtual const bool& get_WebAttackMitigation() const = 0; virtual const bool& get_WebAttackMitigation() const = 0;
virtual const std::string& get_WebAttackMitigationAction() const = 0; virtual const std::string& get_WebAttackMitigationAction() const = 0;
virtual const std::vector<std::string> & get_applicationUrls() const = 0;
virtual const std::shared_ptr<Waap::Override::Policy>& get_OverridePolicy() const = 0; virtual const std::shared_ptr<Waap::Override::Policy>& get_OverridePolicy() const = 0;
virtual const std::shared_ptr<Waap::Trigger::Policy>& get_TriggerPolicy() const = 0; virtual const std::shared_ptr<Waap::Trigger::Policy>& get_TriggerPolicy() const = 0;

View File

@ -253,6 +253,12 @@ void WaapConfigBase::loadOpenRedirectPolicy(cereal::JSONInputArchive& ar)
} }
const std::vector<std::string> &
WaapConfigBase::get_applicationUrls() const
{
return m_applicationUrls;
}
void WaapConfigBase::loadErrorDisclosurePolicy(cereal::JSONInputArchive& ar) void WaapConfigBase::loadErrorDisclosurePolicy(cereal::JSONInputArchive& ar)
{ {
std::string failMessage = "Failed to load the WAAP Information Disclosure policy"; std::string failMessage = "Failed to load the WAAP Information Disclosure policy";

View File

@ -45,6 +45,7 @@ public:
virtual const std::string& get_RuleName() const; virtual const std::string& get_RuleName() const;
virtual const bool& get_WebAttackMitigation() const; virtual const bool& get_WebAttackMitigation() const;
virtual const std::string& get_WebAttackMitigationAction() const; virtual const std::string& get_WebAttackMitigationAction() const;
virtual const std::vector<std::string> & get_applicationUrls() const;
virtual const std::shared_ptr<Waap::Override::Policy>& get_OverridePolicy() const; virtual const std::shared_ptr<Waap::Override::Policy>& get_OverridePolicy() const;
virtual const std::shared_ptr<Waap::Trigger::Policy>& get_TriggerPolicy() const; virtual const std::shared_ptr<Waap::Trigger::Policy>& get_TriggerPolicy() const;

View File

@ -21,6 +21,7 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <dirent.h> #include <dirent.h>
#include <sstream> #include <sstream>
#include <algorithm>
#include "debug.h" #include "debug.h"
@ -49,6 +50,24 @@ exists(const string &path)
return false; 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 bool
makeDir(const string &path, mode_t permission) makeDir(const string &path, mode_t permission)
{ {
@ -356,4 +375,20 @@ regexReplace(const char *file, int line, const string &sample, const regex &rege
}// namespace Regex }// 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 } // namespace NGEN

View File

@ -98,8 +98,20 @@ TEST_F(AgentCoreUtilUT, printTest)
EXPECT_EQ(NGEN::Filesystem::convertToHumanReadable(1024*gigabyte), "1024.00 GB"); EXPECT_EQ(NGEN::Filesystem::convertToHumanReadable(1024*gigabyte), "1024.00 GB");
} }
TEST_F(AgentCoreUtilUT, fileBasenameTest) TEST_F(AgentCoreUtilUT, fileBasenameTest)
{ {
EXPECT_EQ(NGEN::Filesystem::getFileName("/test/base/file/name"), "name"); 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");
}

View File

@ -141,7 +141,6 @@ Environment::Impl::init()
void void
Environment::Impl::fini() Environment::Impl::fini()
{ {
global.deactivate();
} }
void void

Some files were not shown because too many files have changed in this diff Show More