Compare commits

...

22 Commits

Author SHA1 Message Date
Ned Wright
1c10a12f6f Minor fixes 2023-09-28 16:40:42 +00:00
Ned Wright
e9f6ebd02b Minor fixes 2023-09-28 16:38:31 +00:00
Ned Wright
433c7c2d91 Remove old files 2023-09-28 13:11:47 +00:00
Ned Wright
582791e37a Sep_24_2023-Dev 2023-09-24 10:28:57 +00:00
Ned Wright
a4d1fb6f7f Ading explict k8s check update invocation 2023-09-19 09:16:27 +00:00
bilbogh
dfbfdca1a9 Update README.md 2023-09-15 10:07:49 +02:00
bilbogh
36f511f449 Update README.md 2023-09-14 23:21:06 +02:00
bilbogh
f91f283b77 Added new section 2023-09-14 22:59:28 +02:00
bilbogh
7c762e97a3 Added charts 2023-09-14 22:36:50 +02:00
Ned Wright
aaa1fbe8ed Adding links to command line tools 2023-09-12 16:42:52 +00:00
Ned Wright
67e68c84c3 Fix finding libraries 2023-09-11 12:40:26 +03:00
Ned Wright
149a7305b7 Remove old deafult fog 2023-09-07 14:54:40 +00:00
Ned Wright
ea20a51689 Add upload option to open-appsec-ctl 2023-09-04 16:15:06 +00:00
bilbogh
19f2383ae2 Update README.md
Brought back lines that were accidentally deleted
2023-09-01 14:18:16 +02:00
WrightNed
4038c18bda Update CMakeLists.txt 2023-08-24 20:26:18 +03:00
WrightNed
a9b6d2e715 Merge pull request #47 from openappsec/Aug_23_2023-Dev
Aug 23 2023 dev
2023-08-24 15:10:14 +03:00
Ned Wright
81c75495cc temporarily disabling some unit-tests 2023-08-24 11:56:16 +00:00
WrightNed
5505022f47 Update cp-nano-package-list 2023-08-23 20:46:45 +03:00
Ned Wright
b25fd8def5 Aug_23_2023-Dev 2023-08-23 14:15:32 +00:00
Ned Wright
702c1184ea Merge branch 'main' of https://github.com/openappsec/openappsec 2023-08-17 17:40:54 +00:00
Ned Wright
b3cfd7e9d8 Check /etc/environment exists before using it 2023-08-17 17:40:22 +00:00
WrightNed
e36b990161 Merge pull request #43 from openappsec/changing_socket_readiness_testing
Change socket readiness testing
2023-08-10 00:22:37 +03:00
187 changed files with 12375 additions and 2739 deletions

134
README.md
View File

@@ -18,25 +18,41 @@ Every request to the application goes through two phases:
2. If the request is identified as a valid and legitimate request the request is allowed, and forwarded to your application. If, however, the request is considered suspicious or high risk, it then gets evaluated by the unsupervised model, which was trained in your specific environment. This model uses information such as the URL and the users involved to create a final confidence score that determines whether the request should be allowed or blocked.
## Machine Learning models
![image](https://github.com/openappsec/openappsec/assets/114033741/f32f1c99-9c45-4d21-aa85-61408a16a18e)
open-appsec uses two models:
open-appsec uses two machine learning models:
1. A supervised model that was trained offline based on millions of requests, both malicious and benign.
* A basic model is provided as part of this repository. It is recommended for use in Monitor-Only and Test environments.
* An advanced model which is more accurate and recommended for Production use can be downloaded from the [open-appsec portal](https://my.openappsec.io)->User Menu->Download advanced ML model. This model updates from time to time and you will get an email when these updates happen.
* A **basic model** is provided as part of this repository. It is recommended for use in Monitor-Only and Test environments.
* An **advanced model** which is more accurate and **recommended for Production** use can be downloaded from the [open-appsec portal](https://my.openappsec.io)->User Menu->Download advanced ML model. This model updates from time to time and you will get an email when these updates happen.
2. An unsupervised model that is being built in real time in the protected environment. This model uses traffic patterns specific to the environment.
# Management
open-appsec can be managed using multiple methods:
* [Declarative configuration files](https://docs.openappsec.io/getting-started/getting-started)
* [Kubernetes Helm Charts and annotations](https://docs.openappsec.io/getting-started/getting-started)
* [Using SaaS Web Management](https://docs.openappsec.io/getting-started/using-the-web-ui-saas)
open-appsec Web UI:
![image](https://github.com/openappsec/openappsec/assets/114033741/22d99379-df52-45c8-984f-1b820635f3b9)
## Deployment Playgrounds (Virtual labs)
You can experiment with open-appsec using [Playgrounds](https://www.openappsec.io/playground)
![image](https://github.com/openappsec/openappsec/assets/114033741/14d35d69-4577-48fc-ae87-ea344888e94d)
# Resources
* [Project Website](https://openappsec.io)
* [Offical Documentation](https://docs.openappsec.io/)
* [Video Tutorials](https://www.openappsec.io/tutorials)
* [Live Playgrounds](https://www.openappsec.io/playground)
# open-appsec Installation
# Installation
For Kubernetes (NGINX Ingress) using the installer:
@@ -63,3 +79,107 @@ $ install-cp-nano-attachment-registration-manager.sh --install
```
You can add the ```--token <token>``` and ```--email <email address>``` options to the first command, to get a token follow [documentation](https://docs.openappsec.io/getting-started/using-the-web-ui-saas/connect-deployed-agents-to-saas-management-k8s-and-linux).
For Docker: follow [documentation](https://docs.openappsec.io/getting-started/start-with-docker)
For more information read the [documentation](https://docs.openappsec.io/) or follow the [video tutorials](https://www.openappsec.io/tutorials).
# Repositories
open-appsec GitHub includes four main repositories:
* [openappsec/openappsec](https://github.com/openappsec/openappsec) the main code and logic of open-appsec. Developed in C++.
* [openappsec/attachment](https://github.com/openappsec/attachment) connects between processes that provide HTTP data (e.g NGINX) and the open-appsec Agent security logic. Developed in C.
* [openappsec/smartsync](https://github.com/openappsec/smartsync) in charge of correlating learning data from multiple agent instances and delivering a unified learning model for each asset. Developed in Golang.
* [openappsec/smartsync-shared-files](https://github.com/openappsec/smartsync-shared-files) interface to physical storage used by smartsync service for storing learning data. Developed in Golang.
# Compilation instructions
## Installing external dependencies
Before compiling the services, you'll need to ensure the latest development versions of the following libraries:
* Boost
* OpenSSL
* PCRE2
* libxml2
* GTest
* GMock
* cURL
* Hiredis
An example of installing the packages on Alpine:
```bash
$ apk update
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev hiredis-dev
```
## Compiling and packaging the agent code
1. Clone this repository
2. Run CMake command
3. Run make install command
```bash
$ git clone https://github.com/openappsec/openappsec.git
$ cd openappsec/
$ cmake -DCMAKE_INSTALL_PREFIX=build_out .
$ make install
$ make package
```
## Placing the agent code inside an Alpine docker image
Once the agent code has been compiled and packaged, an Alpine image running it can be created. This requires permissions to execute the `docker` command.
```bash
$ make docker
```
This will create a local image for your docker called `agent-docker`.
## Deployment of the agent docker image as a container
To run a Nano-Agent as a container the following steps are required:
1. If you are using a container management system / plan on deploying the container using your CI, add the agent docker image to an accessible registry.
2. If you are planning to manage the agent using the open-appsec UI, then make sure to obtain an agent token from the Management Portal and Enforce.
3. Run the agent with the following command (where -e https_proxy parameter is optional):
`docker run -d --name=agent-container --ipc=host -v=<path to persistent location for agent config>:/etc/cp/conf -v=<path to persistent location for agent data files>:/etc/cp/data -v=<path to persistent location for agent debugs and logs>:/var/log/nano_agent -e https_proxy=<user:password@Proxy address:port> -it <agent-image> /cp-nano-agent [--token <token> | --standalone]`
Example:
```bash
$ docker run -d --name=agent-container --ipc=host -v=/home/admin/agent/conf:/etc/cp/conf -v=/home/admin/agent/data:/etc/cp/data -v=/home/admin/agent/logs:/var/log/nano_agent e https_proxy=user:password@1.2.3.4:8080 -it agent-docker /cp-nano-agent --standalone
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e67f2abbfd4 agent-docker "/cp-nano-agent --hybrid-mode" 1 minute ago Up 1 minute agent-container
```
Note that you are not required to use a token from the Management Portal if you are managing your security policy locally. However, you are required to use the --standalone flag in such cases. In addition, the volumes in the command are mandatory only if you wish to have persistency upon restart/upgrade/crash of the agent and its re-execution.
Lastly, --ipc=host argument is mandatory in order for the agent to have access to shared memory with a protected attachment (NGINX server).
4. Create or replace the NGINX container using the [Attachment Repository](https://github.com/openappsec/attachment).
This will run a docker container using the agent docker image.
# Contributing
We welcome everyone that wishes to share their knowledge and expertise to enhance and expand the project.
Please see the [Contributing Guidelines](https://github.com/openappsec/openappsec/blob/main/CONTRIBUTING.md).
# Security
### Security Audit
open-appsec code was audited by an independent third party in September-October 2022.
See the [full report](https://github.com/openappsec/openappsec/blob/main/LEXFO-CHP20221014-Report-Code_audit-OPEN-APPSEC-v1.2.pdf).
### Reporting security vulnerabilities
If you've found a vulnerability or a potential vulnerability in open-appsec please let us know at securityalert@openappsec.io. We'll send a confirmation email to acknowledge your report within 24 hours, and we'll send an additional email when we've identified the issue positively or negatively.
# License
open-appsec is open source and available under Apache 2.0 license.
The basic ML model is open source and available under Apache 2.0 license.
The advanced ML model is open source and available under Machine Learning Model license, available upon download in the tar file.

View File

@@ -58,6 +58,10 @@ fi
/nano-service-installers/$ORCHESTRATION_INSTALLATION_SCRIPT --install $orchestration_service_installation_flags
if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then
/etc/cp/orchestration/k8s-check-update-listener.sh &
fi
/nano-service-installers/$ATTACHMENT_REGISTRATION_SERVICE --install
/nano-service-installers/$HTTP_TRANSACTION_HANDLER_SERVICE --install

View File

@@ -1762,8 +1762,8 @@ private:
&did_fail_on_purpose
)) {
return genError(
"Failed to read the attachment's User ID or Group ID" +
did_fail_on_purpose ? "[Intentional Failure]" : ""
string("Failed to read the attachment's User ID or Group ID") +
(did_fail_on_purpose ? "[Intentional Failure]" : "")
);
}

View File

@@ -20,6 +20,9 @@
#include "environment/evaluator_templates.h"
#include "i_environment.h"
#include "singleton.h"
#include "debug.h"
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
using namespace std;
using namespace EnvironmentHelper;
@@ -55,6 +58,51 @@ EqualHost::evalVariable() const
return lower_host_ctx == lower_host;
}
WildcardHost::WildcardHost(const vector<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)
{
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1);

View File

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

View File

@@ -156,7 +156,7 @@ Zone::contains(const Asset &asset)
{
QueryRequest request;
for (const pair<Context::MetaDataType, string> &main_attr : asset.getAttrs()) {
for (const auto &main_attr : asset.getAttrs()) {
request.addCondition(Condition::EQUALS, contextKeyToString(main_attr.first), main_attr.second);
}

View File

@@ -83,13 +83,13 @@ public:
:
status(raw_status)
{
for (const pair<string, HealthCheckStatusReply> &single_stat : descriptions) {
for (const auto &single_stat : descriptions) {
if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) {
dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first;
continue;
}
for (const pair<string, string> &status : single_stat.second.getExtendedStatus()) {
for (const auto &status : single_stat.second.getExtendedStatus()) {
errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second));
}
}
@@ -190,7 +190,7 @@ private:
{
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
for (const pair<string, HealthCheckStatusReply> &reply : all_comps_health_status) {
for (const auto &reply : all_comps_health_status) {
HealthCheckStatus status = reply.second.getStatus();
dbgTrace(D_HEALTH_CHECK_MANAGER)

View File

@@ -48,7 +48,7 @@ HttpManagerOpaque::getCurrVerdict() const
uint accepted_apps = 0;
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
for (const pair<string, ngx_http_cp_verdict_e> &app_verdic_pair : applications_verdicts) {
for (const auto &app_verdic_pair : applications_verdicts) {
switch (app_verdic_pair.second) {
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP:
return app_verdic_pair.second;

View File

@@ -32,6 +32,19 @@ private:
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>
{
public:

View File

@@ -11,52 +11,108 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/// \file triggers_config.h
/// \brief Declaration of classes WebTriggerConf and LogTriggerConf, and related functions.
/// \author Check Point Software Technologies Ltd.
/// \date 2022
#ifndef __TRIGGERS_CONFIG_H__
#define __TRIGGERS_CONFIG_H__
#include <vector>
#include <string>
#include <vector>
#include "environment/evaluator_templates.h"
#include "cereal/archives/json.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/archives/json.hpp"
#include "config.h"
#include "environment/evaluator_templates.h"
#include "generic_rulebase_utils.h"
#include "i_environment.h"
#include "i_logging.h"
#include "singleton.h"
#include "maybe_res.h"
#include "config.h"
#include "log_generator.h"
#include "generic_rulebase_utils.h"
#include "maybe_res.h"
#include "singleton.h"
/// \class WebTriggerConf
/// \brief Represents the configuration for a web trigger.
class WebTriggerConf
{
public:
/// \brief Default constructor for WebTriggerConf.
WebTriggerConf();
/// \brief Constructor for WebTriggerConf.
/// \param title The title of the trigger.
/// \param body The body of the trigger.
/// \param code The response code for the trigger.
WebTriggerConf(const std::string &title, const std::string &body, uint code);
/// \brief Preload function to register expected configuration.
static void
preload()
{
registerExpectedConfiguration<WebTriggerConf>("rulebase", "webUserResponse");
}
/// \brief Load function to deserialize configuration from JSONInputArchive.
/// \param archive_in The JSON input archive.
void load(cereal::JSONInputArchive &archive_in);
/// \brief Equality operator for WebTriggerConf.
/// \param other The WebTriggerConf to compare.
/// \return True if the two WebTriggerConf objects are equal, otherwise false.
bool operator==(const WebTriggerConf &other) const;
uint getResponseCode() const { return response_code; }
/// \brief Get the response code for the trigger.
/// \return The response code.
uint
getResponseCode() const
{
return response_code;
}
const std::string & getResponseTitle() const { return response_title; }
/// \brief Get the response title for the trigger.
/// \return The response title.
const std::string &
getResponseTitle() const
{
return response_title;
}
const std::string & getResponseBody() const { return response_body; }
/// \brief Get the response body for the trigger.
/// \return The response body.
const std::string &
getResponseBody() const
{
return response_body;
}
const std::string & getDetailsLevel() const { return details_level; }
/// \brief Get the details level for the trigger.
/// \return The details level.
const std::string &
getDetailsLevel() const
{
return details_level;
}
const std::string & getRedirectURL() const { return redirect_url; }
/// \brief Get the redirect URL for the trigger.
/// \return The redirect URL.
const std::string &
getRedirectURL() const
{
return redirect_url;
}
bool getAddEventId() const { return add_event_id_to_header; }
/// \brief Check if the trigger should add an event ID to the header.
/// \return True if the trigger should add an event ID, otherwise false.
bool
getAddEventId() const
{
return add_event_id_to_header;
}
/// \brief Default trigger configuration for WebTriggerConf.
static WebTriggerConf default_trigger_conf;
private:
@@ -64,17 +120,38 @@ private:
std::string details_level;
std::string response_body;
std::string redirect_url;
uint response_code;
bool add_event_id_to_header = false;
uint response_code;
bool add_event_id_to_header = false;
};
/// \class LogTriggerConf
/// \brief Represents the configuration for a log trigger.
class LogTriggerConf : Singleton::Consume<I_Logging>
{
public:
enum class SecurityType { AccessControl, ThreatPrevention, Compliance, COUNT };
enum class extendLoggingSeverity { None, High, Critical };
/// \enum SecurityType
/// \brief Enumerates the security types for LogTriggerConf.
enum class SecurityType
{
AccessControl,
ThreatPrevention,
Compliance,
COUNT
};
enum class WebLogFields {
/// \enum extendLoggingSeverity
/// \brief Enumerates the extended logging severity for LogTriggerConf.
enum class extendLoggingSeverity
{
None,
High,
Critical
};
/// \enum WebLogFields
/// \brief Enumerates the web log fields for LogTriggerConf.
enum class WebLogFields
{
webBody,
webHeaders,
webRequests,
@@ -85,17 +162,31 @@ public:
COUNT
};
/// \brief Default constructor for LogTriggerConf.
LogTriggerConf() {}
/// \brief Constructor for LogTriggerConf.
/// \param trigger_name The name of the trigger.
/// \param log_detect Flag indicating whether to log on detect.
/// \param log_prevent Flag indicating whether to log on prevent.
LogTriggerConf(std::string trigger_name, bool log_detect, bool log_prevent);
/// \brief Preload function to register expected configuration.
static void
preload()
{
registerExpectedConfiguration<LogTriggerConf>("rulebase", "log");
}
template <typename ...Tags>
/// \brief LogGen operator for LogTriggerConf.
/// \param title The title of the log.
/// \param security The security type of the log.
/// \param severity The severity of the log.
/// \param priority The priority of the log.
/// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent.
/// \param tags Tags for the log.
/// \return The LogGen object.
template <typename... Tags>
LogGen
operator()(
const std::string &title,
@@ -103,7 +194,8 @@ public:
ReportIS::Severity severity,
ReportIS::Priority priority,
bool is_action_drop_or_prevent,
Tags ...tags) const
Tags... tags
) const
{
return LogGen(
title,
@@ -117,11 +209,17 @@ public:
);
}
template <typename ...Tags>
/// \brief LogGen operator for LogTriggerConf.
/// \param title The title of the log.
/// \param security The security type of the log.
/// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent.
/// \param tags Tags for the log.
/// \return The LogGen object.
template <typename... Tags>
LogGen
operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags ...tags) const
operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags... tags) const
{
return (*this)(
return operator()(
title,
security,
getSeverity(is_action_drop_or_prevent),
@@ -131,30 +229,98 @@ public:
);
}
/// \brief Load function to deserialize configuration from JSONInputArchive.
/// \param archive_in The JSON input archive.
void load(cereal::JSONInputArchive &archive_in);
bool isWebLogFieldActive(WebLogFields log_field) const { return log_web_fields.isSet(log_field); }
/// \brief Check if the web log field is active for the trigger.
/// \param log_field The web log field to check.
/// \return True if the web log field is active, otherwise false.
bool
isWebLogFieldActive(WebLogFields log_field) const
{
return log_web_fields.isSet(log_field);
}
bool isLogStreamActive(ReportIS::StreamType stream_type) const { return active_streams.isSet(stream_type); }
/// \brief Check if the log stream is active for the trigger.
/// \param stream_type The log stream type to check.
/// \return True if the log stream is active, otherwise false.
bool
isLogStreamActive(ReportIS::StreamType stream_type) const
{
return active_streams.isSet(stream_type);
}
bool isPreventLogActive(SecurityType security_type) const { return should_log_on_prevent.isSet(security_type); }
/// \brief Check if the log is active on prevent for the given security type.
/// \param security_type The security type to check.
/// \return True if the log is active on prevent, otherwise false.
bool
isPreventLogActive(SecurityType security_type) const
{
return should_log_on_prevent.isSet(security_type);
}
bool isDetectLogActive(SecurityType security_type) const { return should_log_on_detect.isSet(security_type); }
/// \brief Check if the log is active on detect for the given security type.
/// \param security_type The security type to check.
/// \return True if the log is active on detect, otherwise false.
bool
isDetectLogActive(SecurityType security_type) const
{
return should_log_on_detect.isSet(security_type);
}
bool isLogGeoLocationActive(SecurityType security_type) const { return log_geo_location.isSet(security_type); }
/// \brief Check if the geo-location log is active for the given security type.
/// \param security_type The security type to check.
/// \return True if the geo-location log is active, otherwise false.
bool
isLogGeoLocationActive(SecurityType security_type) const
{
return log_geo_location.isSet(security_type);
}
extendLoggingSeverity getExtendLoggingSeverity() const { return extend_logging_severity; }
/// \brief Get the extended logging severity.
/// \return The extended logging severity.
extendLoggingSeverity
getExtendLoggingSeverity() const
{
return extend_logging_severity;
}
const std::string & getVerbosity() const { return verbosity; }
const std::string & getName() const { return name; }
/// \brief Get the verbosity.
/// \return The verbosity.
const std::string &
getVerbosity() const
{
return verbosity;
}
const std::string & getUrlForSyslog() const { return url_for_syslog; }
const std::string & getUrlForCef() const { return url_for_cef; }
/// \brief Get the name.
/// \return The name.
const std::string &
getName() const
{
return name;
}
/// \brief Get the URL for syslog.
/// \return The URL for syslog.
const std::string &
getUrlForSyslog() const
{
return url_for_syslog;
}
/// \brief Get the URL for CEF.
/// \return The URL for CEF.
const std::string &
getUrlForCef() const
{
return url_for_cef;
}
private:
ReportIS::Severity getSeverity(bool is_action_drop_or_prevent) const;
ReportIS::Priority getPriority(bool is_action_drop_or_prevent) const;
Flags<ReportIS::StreamType> getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const;
Flags<ReportIS::Enreachments> getEnrechments(SecurityType security_type) const;

View File

@@ -18,6 +18,7 @@
#include "i_mainloop.h"
#include "i_socket_is.h"
#include "i_health_check_manager.h"
#include "i_shell_cmd.h"
#include "component.h"
class HealthChecker
@@ -25,7 +26,8 @@ class HealthChecker
public Component,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_Socket>,
Singleton::Consume<I_Health_Check_Manager>
Singleton::Consume<I_Health_Check_Manager>,
Singleton::Consume<I_ShellCmd>
{
public:
HealthChecker();

View File

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

View File

@@ -34,6 +34,7 @@ public:
virtual const std::string & getUpdateTime() const = 0;
virtual const std::string & getLastManifestUpdate() const = 0;
virtual const std::string & getPolicyVersion() const = 0;
virtual const std::string & getWaapModelVersion() const = 0;
virtual const std::string & getLastPolicyUpdate() const = 0;
virtual const std::string & getLastSettingsUpdate() const = 0;
virtual const std::string & getUpgradeMode() const = 0;

View File

@@ -106,11 +106,18 @@ public:
const std::string &profile_id = "") 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 bool writeFile(const std::string &text, const std::string &path) const = 0;
virtual bool writeFile(const std::string &text, const std::string &path, bool append_mode = false) const = 0;
virtual bool removeFile(const std::string &path) const = 0;
virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0;
virtual void deleteVirtualTenantProfileFiles(
const std::string &tenant_id,
const std::string &profile_id,
const std::string &conf_path) const = 0;
virtual bool copyFile(const std::string &src_path, const std::string &dst_path) const = 0;
virtual bool doesFileExist(const std::string &file_path) const = 0;
virtual void getClusterId() const = 0;
virtual void fillKeyInJson(
const std::string &filename,
const std::string &_key,
@@ -118,6 +125,7 @@ public:
virtual bool createDirectory(const std::string &directory_path) const = 0;
virtual bool doesDirectoryExist(const std::string &dir_path) const = 0;
virtual bool executeCmd(const std::string &cmd) const = 0;
virtual void loadTenantsFromDir(const std::string &dir_path) const = 0;
virtual std::string base64Encode(const std::string &input) const = 0;
virtual std::string base64Decode(const std::string &input) const = 0;

View File

@@ -19,6 +19,7 @@
#include <map>
#include "connkey.h"
#include "maybe_res.h"
#include "rest.h"
enum class ReconfStatus { SUCCEEDED, IN_PROGRESS, FAILED, INACTIVE };
@@ -27,6 +28,7 @@ class I_ServiceController
{
public:
virtual void refreshPendingServices() = 0;
virtual const std::string & getPolicyVersions() const = 0;
virtual const std::string & getPolicyVersion() const = 0;
virtual const std::string & getUpdatePolicyVersion() const = 0;
virtual void updateReconfStatus(int id, ReconfStatus status) = 0;
@@ -37,13 +39,13 @@ public:
const std::string &service_id
) = 0;
virtual bool
virtual Maybe<void>
updateServiceConfiguration(
const std::string &new_policy_path,
const std::string &new_settings_path,
const std::vector<std::string> &new_data_files = {},
const std::string &tenant_id = "",
const std::string &profile_id = "",
const std::string &child_tenant_id = "",
const std::string &child_profile_id = "",
const bool last_iteration = false
) = 0;

View File

@@ -26,9 +26,12 @@ using OrchData = Maybe<std::string>;
class I_UpdateCommunication
{
public:
virtual Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const = 0;
virtual Maybe<void> authenticateAgent() = 0;
virtual Maybe<void> getUpdate(CheckUpdateRequest &request) = 0;
virtual Maybe<void> sendPolicyVersion(const std::string &policy_version) const = 0;
virtual Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) = 0;
virtual void setAddressExtenesion(const std::string &extension) = 0;
};

View File

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

View File

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

View File

@@ -17,9 +17,26 @@
#include <fstream>
#include "i_orchestration_tools.h"
#include "i_shell_cmd.h"
#include "i_tenant_manager.h"
#include "component.h"
#include "i_env_details.h"
#include "i_messaging.h"
#include "i_environment.h"
#include "i_agent_details.h"
#include "i_mainloop.h"
class OrchestrationTools : public Component, Singleton::Provide<I_OrchestrationTools>
class OrchestrationTools
:
public Component,
Singleton::Provide<I_OrchestrationTools>,
Singleton::Consume<I_ShellCmd>,
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:
OrchestrationTools();

View File

@@ -106,6 +106,78 @@ public:
BOTH_LABEL_OPTIONAL_PARAM(TenantError, error, "error");
};
class UpgradeSchedule : public ClientRest
{
public:
UpgradeSchedule() = default;
UpgradeSchedule(const UpgradeSchedule &other)
{
mode = other.mode;
time = other.time;
duration_hours = other.duration_hours;
days = other.days;
}
UpgradeSchedule &
operator=(const UpgradeSchedule &other)
{
if (this != &other) {
mode = other.mode;
time = other.time;
duration_hours = other.duration_hours;
days = other.days;
}
return *this;
}
void init(const std::string &_upgrade_mode) { mode = _upgrade_mode; }
void
init(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours)
{
init(_upgrade_mode);
time = _upgrade_time;
duration_hours = _upgrade_duration_hours;
}
void
init(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours,
const std::vector<std::string> &_upgrade_days)
{
init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours);
days = _upgrade_days;
}
private:
C2S_LABEL_PARAM(std::string, mode, "upgradeMode");
C2S_LABEL_OPTIONAL_PARAM(std::string, time, "upgradeTime");
C2S_LABEL_OPTIONAL_PARAM(uint, duration_hours, "upgradeDurationHours");
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(
const std::string &_manifest,
const std::string &_policy,
@@ -185,6 +257,32 @@ public:
void setGreedyMode() { check_all_tenants = true; }
void
setUpgradeFields(const std::string &_upgrade_mode)
{
UpgradeSchedule upgrade_schedule;
upgrade_schedule.init(_upgrade_mode);
local_configuration_settings.setActive(true);
local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule);
}
void
setUpgradeFields(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours,
const std::vector<std::string> &_upgrade_days)
{
UpgradeSchedule upgrade_schedule;
if (!_upgrade_days.empty()) {
upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days);
} else {
upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours);
}
local_configuration_settings.setActive(true);
local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule);
}
private:
class VirtualConfig : public ClientRest
{
@@ -239,6 +337,8 @@ private:
C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type");
C2S_LABEL_PARAM(std::string, policy_version, "policyVersion");
C2S_LABEL_OPTIONAL_PARAM(LocalConfigurationSettings, local_configuration_settings, "localConfigurationSettings");
S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_policy, "virtualPolicy");
S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings");
};

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(layer_7_access_control)
add_subdirectory(local_policy_mgmt_gen)
add_subdirectory(orchestration)
add_subdirectory(rate_limit)
add_subdirectory(waap)

View File

@@ -1,54 +1,176 @@
// 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.
/// \file ips_signatures.h
/// \brief Declaration of classes IPSSignatureSubTypes, IPSSignaturesPerContext, IPSSignatures, SnortSignatures, and
/// related functions. \author Check Point Software Technologies Ltd. \date 2022
#ifndef __IPS_SIGNATURES_H__
#define __IPS_SIGNATURES_H__
#include <vector>
#include "config.h"
#include "parsed_context.h"
#include "log_generator.h"
#include "pm_hook.h"
#include "ips_enums.h"
#include "ips_entry.h"
#include "i_first_tier_agg.h"
#include "ips_entry.h"
#include "ips_enums.h"
#include "log_generator.h"
#include "parsed_context.h"
#include "pm_hook.h"
/// \namespace IPSSignatureSubTypes
/// \brief Namespace containing subtypes for IPS signatures.
namespace IPSSignatureSubTypes
{
using ActionResults = std::tuple<IPSSignatureSubTypes::SignatureAction, std::string, std::vector<std::string>>;
/// \class BaseSignature
/// \brief Represents the base signature class.
class BaseSignature
{
public:
enum class MatchType { NO_MATCH, CACHE_MATCH, MATCH };
/// \enum MatchType
/// \brief Enumerates the types of matches for BaseSignature.
enum class MatchType
{
NO_MATCH,
CACHE_MATCH,
MATCH
};
virtual const std::string & getSigId() const = 0;
/// \brief Get the ID of the signature.
virtual const std::string &getSigId() const = 0;
/// \brief Get the match type for the signature.
/// \param matched The set of patterns that matched.
virtual MatchType getMatch(const std::set<PMPattern> &matched) const = 0;
/// \brief Get the set of patterns in the signature.
virtual std::set<PMPattern> patternsInSignature() const = 0;
virtual const std::vector<std::string> & getContext() const = 0;
/// \brief Get the context of the signature.
virtual const std::vector<std::string> &getContext() const = 0;
};
/// \class IPSSignatureMetaData
/// \brief Represents the metadata for an IPS signature.
class IPSSignatureMetaData
{
public:
/// \brief Load the metadata from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Set the indicators for the metadata.
/// \param source The source indicator.
/// \param version The version indicator.
void setIndicators(const std::string &source, const std::string &version);
const std::string & getId() const { return protection_id; }
const std::string & getName() const { return sig_name; }
const std::string & getUpdateVersion() const { return update; }
const std::string & getLogTitle() const { return event_log; }
const std::string & getSource() const { return source; }
const std::string & getFeedVersion() const { return version; }
const std::vector<std::string> & getCveList() const { return cve_list; }
IPSLevel getSeverity() const { return severity; }
std::string getSeverityString() const;
IPSLevel getConfidence() const { return confidence; }
std::string getConfidenceString() const;
IPSLevel getPerformance() const { return performance; }
std::string getPerformanceString() const;
bool isSilent() const { return is_silent; }
std::string getIncidentType() const;
bool isYearAtLeast(const Maybe<int> &year) const;
Maybe<int> getYear() const;
/// \brief Get the ID of the signature.
const std::string &
getId() const
{
return protection_id;
}
/// \brief Get the name of the signature.
const std::string &
getName() const
{
return sig_name;
}
/// \brief Get the update version of the signature.
const std::string &
getUpdateVersion() const
{
return update;
}
/// \brief Get the log title of the signature.
const std::string &
getLogTitle() const
{
return event_log;
}
/// \brief Get the source indicator of the signature.
const std::string &
getSource() const
{
return source;
}
/// \brief Get the feed version of the signature.
const std::string &
getFeedVersion() const
{
return version;
}
/// \brief Get the CVE list of the signature.
const std::vector<std::string> &
getCveList() const
{
return cve_list;
}
/// \brief Get the severity level of the signature.
IPSLevel
getSeverity() const
{
return severity;
}
/// \brief Get the severity level as a string of the signature.
std::string getSeverityString() const;
/// \brief Get the confidence level of the signature.
IPSLevel
getConfidence() const
{
return confidence;
}
/// \brief Get the confidence level as a string of the signature.
std::string getConfidenceString() const;
/// \brief Get the performance level of the signature.
IPSLevel
getPerformance() const
{
return performance;
}
/// \brief Get the performance level as a string of the signature.
std::string getPerformanceString() const;
/// \brief Check if the signature is silent.
bool
isSilent() const
{
return is_silent;
}
/// \brief Get the incident type of the signature.
std::string getIncidentType() const;
/// \brief Check if the signature is from a specific year or later.
/// \param year The year to compare with.
bool isYearAtLeast(const Maybe<int> &year) const;
/// \brief Get the year of the signature.
Maybe<int> getYear() const;
private:
std::string protection_id;
@@ -65,69 +187,224 @@ private:
bool is_silent = false;
};
/// \class CompleteSignature
/// \brief Represents a complete signature.
class CompleteSignature
{
public:
/// \brief Load the complete signature from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get the match type for the signature.
/// \param matches The set of patterns that matched.
BaseSignature::MatchType getMatch(const std::set<PMPattern> &matches) const;
/// \brief Get the set of patterns in the signature.
std::set<PMPattern> patternsInSignature() const;
/// \brief Set the indicators for the complete signature.
/// \param source The source indicator.
/// \param version The version indicator.
void setIndicators(const std::string &source, const std::string &version);
const std::vector<std::string> & getContext() const { return rule->getContext(); }
const std::string & getId() const { return metadata.getId(); }
const std::string & getLogTitle() const { return metadata.getLogTitle(); }
const std::string & getName() const { return metadata.getName(); }
const std::string & getUpdateVersion() const { return metadata.getUpdateVersion(); }
const std::string & getSource() const { return metadata.getSource(); }
const std::string & getFeedVersion() const { return metadata.getFeedVersion(); }
const std::vector<std::string> & getCveList() const { return metadata.getCveList(); }
IPSLevel getSeverity() const { return metadata.getSeverity(); }
std::string getSeverityString() const { return metadata.getSeverityString(); }
IPSLevel getConfidence() const { return metadata.getConfidence(); }
std::string getConfidenceString() const { return metadata.getConfidenceString(); }
IPSLevel getPerformance() const { return metadata.getPerformance(); }
std::string getPerformanceString() const { return metadata.getPerformanceString(); }
bool isSilent() const { return metadata.isSilent(); }
std::string getIncidentType() const { return metadata.getIncidentType(); }
/// \brief Get the context of the signature.
const std::vector<std::string> &
getContext() const
{
return rule->getContext();
}
bool isYearAtLeast(const Maybe<int> &year) const { return metadata.isYearAtLeast(year); }
Maybe<int> getYear() const { return metadata.getYear(); }
/// \brief Get the ID of the signature.
const std::string &
getId() const
{
return metadata.getId();
}
/// \brief Get the log title of the signature.
const std::string &
getLogTitle() const
{
return metadata.getLogTitle();
}
/// \brief Get the name of the signature.
const std::string &
getName() const
{
return metadata.getName();
}
/// \brief Get the update version of the signature.
const std::string &
getUpdateVersion() const
{
return metadata.getUpdateVersion();
}
/// \brief Get the source indicator of the signature.
const std::string &
getSource() const
{
return metadata.getSource();
}
/// \brief Get the feed version of the signature.
const std::string &
getFeedVersion() const
{
return metadata.getFeedVersion();
}
/// \brief Get the CVE list of the signature.
const std::vector<std::string> &
getCveList() const
{
return metadata.getCveList();
}
/// \brief Get the severity level of the signature.
IPSLevel
getSeverity() const
{
return metadata.getSeverity();
}
/// \brief Get the severity level as a string of the signature.
std::string
getSeverityString() const
{
return metadata.getSeverityString();
}
/// \brief Get the confidence level of the signature.
IPSLevel
getConfidence() const
{
return metadata.getConfidence();
}
/// \brief Get the confidence level as a string of the signature.
std::string
getConfidenceString() const
{
return metadata.getConfidenceString();
}
/// \brief Get the performance level of the signature.
IPSLevel
getPerformance() const
{
return metadata.getPerformance();
}
/// \brief Get the performance level as a string of the signature.
std::string
getPerformanceString() const
{
return metadata.getPerformanceString();
}
/// \brief Check if the signature is silent.
bool
isSilent() const
{
return metadata.isSilent();
}
/// \brief Get the incident type of the signature.
std::string
getIncidentType() const
{
return metadata.getIncidentType();
}
/// \brief Check if the signature is from a specific year or later.
/// \param year The year to compare with.
bool
isYearAtLeast(const Maybe<int> &year) const
{
return metadata.isYearAtLeast(year);
}
/// \brief Get the year of the signature.
Maybe<int>
getYear() const
{
return metadata.getYear();
}
private:
IPSSignatureMetaData metadata;
std::shared_ptr<BaseSignature> rule;
};
/// \class SignatureAndAction
/// \brief Represents a signature and its associated action.
class SignatureAndAction
{
public:
SignatureAndAction(std::shared_ptr<CompleteSignature> _signature, SignatureAction _action)
:
signature(_signature),
action(_action)
/// \brief Construct a SignatureAndAction object.
/// \param _signature The complete signature.
/// \param _action The signature action.
SignatureAndAction(std::shared_ptr<CompleteSignature> _signature, SignatureAction _action) :
signature(_signature), action(_action)
{}
/// \brief Check if the signature is matched for prevention.
/// \param context_buffer The context buffer.
/// \param pattern The set of patterns to match.
bool isMatchedPrevent(const Buffer &context_buffer, const std::set<PMPattern> &pattern) const;
/// \brief Check if the signature is matched silently.
/// \param context_buffer The context buffer.
bool matchSilent(const Buffer &context_buffer) const;
/// \brief Get the set of patterns in the signature.
std::set<PMPattern>
patternsInSignature() const
{
return signature->patternsInSignature();
}
bool isMatchedPrevent(const Buffer &context_buffer, const std::set<PMPattern> &pattern) const;
bool matchSilent(const Buffer &context_buffer) const;
std::set<PMPattern> patternsInSignature() const { return signature->patternsInSignature(); }
const std::vector<std::string> & getContext() const { return signature->getContext(); }
/// \brief Get the context of the signature.
const std::vector<std::string> &
getContext() const
{
return signature->getContext();
}
private:
/// \brief Get the action results for the IPS state.
/// \param ips_state The IPS entry.
ActionResults getAction(const IPSEntry &ips_state) const;
std::shared_ptr<CompleteSignature> signature;
SignatureAction action;
};
} // IPSSignatureSubTypes
} // namespace IPSSignatureSubTypes
/// \class IPSSignaturesPerContext
/// \brief Represents IPS signatures per context.
class IPSSignaturesPerContext : public Singleton::Consume<I_FirstTierAgg>
{
public:
/// \brief Add a signature to the context.
/// \param sig The signature and its associated action.
void addSignature(const IPSSignatureSubTypes::SignatureAndAction &sig);
/// \brief Check if the context is matched for prevention.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const Buffer &context_buffer) const;
/// \brief Calculate the first tier for the given context name.
/// \param ctx_name The context name.
void calcFirstTier(const std::string &ctx_name);
private:
/// \brief Get the first tier matches for the buffer.
/// \param buffer The buffer to match.
std::set<PMPattern> getFirstTierMatches(const Buffer &buffer) const;
std::map<PMPattern, std::vector<IPSSignatureSubTypes::SignatureAndAction>> signatures_per_lss;
@@ -135,11 +412,17 @@ private:
std::shared_ptr<PMHook> first_tier;
};
/// \class IPSSignaturesResource
/// \brief Represents IPS signatures resource.
class IPSSignaturesResource
{
public:
/// \brief Load the IPS signatures resource from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get all the signatures.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -150,11 +433,26 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> all_signatures;
};
/// \class SnortSignaturesResourceFile
/// \brief Represents Snort signatures resource file.
class SnortSignaturesResourceFile
{
public:
/// \brief Load the Snort signatures resource file from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
bool isFile(const std::string &file_name) const { return file_name == name; }
/// \brief Check if the file name matches.
/// \param file_name The name of the file.
/// \return True if the file name matches, otherwise false.
bool
isFile(const std::string &file_name) const
{
return file_name == name;
}
/// \brief Get all the signatures.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -166,11 +464,18 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> all_signatures;
};
/// \class SnortSignaturesResource
/// \brief Represents Snort signatures resource.
class SnortSignaturesResource
{
public:
/// \brief Load the Snort signatures resource from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get all the signatures for the given file name.
/// \param file_name The name of the file.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures(const std::string &file_name) const
{
@@ -185,21 +490,74 @@ private:
std::vector<SnortSignaturesResourceFile> files;
};
/// \class IPSSignatures
/// \brief Represents IPS signatures.
class IPSSignatures
{
std::set<PMPattern> getFirstTier(const ParsedContext &context);
public:
/// \brief Load the IPS signatures from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Check if the context is matched for prevention.
/// \param context_name The name of the context.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const;
bool isEmpty() const { return signatures_per_context.empty(); }
/// \brief Check if the IPS signatures are empty.
/// \return True if the signatures are empty, otherwise false.
bool
isEmpty() const
{
return signatures_per_context.empty();
}
/// \brief Check if the IPS signatures for the given context are empty.
/// \param context The name of the context.
/// \return True if the signatures for the context are empty, otherwise false.
bool isEmpty(const std::string &context) const;
const std::string & getAsset() const { return asset_name; }
const std::string & getAssetId() const { return asset_id; }
const std::string & getPractice() const { return practice_name; }
const std::string & getPracticeId() const { return practice_id; }
const std::string & getSourceIdentifier() const { return source_id; }
/// \brief Get the asset name.
/// \return The asset name.
const std::string &
getAsset() const
{
return asset_name;
}
/// \brief Get the asset ID.
/// \return The asset ID.
const std::string &
getAssetId() const
{
return asset_id;
}
/// \brief Get the practice name.
/// \return The practice name.
const std::string &
getPractice() const
{
return practice_name;
}
/// \brief Get the practice ID.
/// \return The practice ID.
const std::string &
getPracticeId() const
{
return practice_id;
}
/// \brief Get the source identifier.
/// \return The source identifier.
const std::string &
getSourceIdentifier() const
{
return source_id;
}
private:
std::map<std::string, IPSSignaturesPerContext> signatures_per_context;
@@ -210,21 +568,74 @@ private:
std::string source_id;
};
/// \class SnortSignatures
/// \brief Represents Snort signatures.
class SnortSignatures
{
std::set<PMPattern> getFirstTier(const ParsedContext &context);
public:
/// \brief Load the Snort signatures from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Check if the context is matched for prevention.
/// \param context_name The name of the context.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const;
bool isEmpty() const { return signatures_per_context.empty(); }
/// \brief Check if the Snort signatures are empty.
/// \return True if the signatures are empty, otherwise false.
bool
isEmpty() const
{
return signatures_per_context.empty();
}
/// \brief Check if the Snort signatures for the given context are empty.
/// \param context The name of the context.
/// \return True if the signatures for the context are empty, otherwise false.
bool isEmpty(const std::string &context) const;
const std::string & getAsset() const { return asset_name; }
const std::string & getAssetId() const { return asset_id; }
const std::string & getPractice() const { return practice_name; }
const std::string & getPracticeId() const { return practice_id; }
const std::string & getSourceIdentifier() const { return source_id; }
/// \brief Get the asset name.
/// \return The asset name.
const std::string &
getAsset() const
{
return asset_name;
}
/// \brief Get the asset ID.
/// \return The asset ID.
const std::string &
getAssetId() const
{
return asset_id;
}
/// \brief Get the practice name.
/// \return The practice name.
const std::string &
getPractice() const
{
return practice_name;
}
/// \brief Get the practice ID.
/// \return The practice ID.
const std::string &
getPracticeId() const
{
return practice_id;
}
/// \brief Get the source identifier.
/// \return The source identifier.
const std::string &
getSourceIdentifier() const
{
return source_id;
}
private:
std::map<std::string, IPSSignaturesPerContext> signatures_per_context;

View File

@@ -23,6 +23,8 @@ using namespace ReportIS;
using namespace std;
using MatchType = BaseSignature::MatchType;
static const LogTriggerConf default_triger;
static const map<IPSLevel, Severity> severities = {
{ IPSLevel::CRITICAL, Severity::CRITICAL },
{ IPSLevel::HIGH, Severity::HIGH },
@@ -396,7 +398,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
dbgDebug(D_IPS) << "Signature matched - sending log";
auto &trigger = getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
auto &trigger = getConfigurationWithDefault(default_triger, "rulebase", "log");
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;

View File

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

View File

@@ -248,7 +248,7 @@ Layer7AccessControlTest::verifyReport(
EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"waapIncidentType\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": 2253734"));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": \"2253734\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAction\": \"ban\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\""));

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

@@ -0,0 +1,245 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "access_control_practice.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_modes = {"prevent", "detect", "inactive"};
static const set<string> valid_units = {"minute", "second"};
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, std::string> key_to_units_val = {
{ "second", "Second"},
{ "minute", "Minute"}
};
void
RateLimitRulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("name", name),
cereal::make_nvp("type", type)
);
}
const string &
RateLimitRulesTriggerSection::getName() const
{
return name;
}
void
RateLimitRulesSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("URI", uri),
cereal::make_nvp("scope", key_to_units_val.at(scope)),
cereal::make_nvp("triggers", triggers),
cereal::make_nvp("limit", limit)
);
}
RateLimitSection::RateLimitSection(
const string &asset_name,
const string &url,
const string &uri,
const std::string &_mode,
const std::string &_practice_id,
const std::string &_name,
const std::vector<RateLimitRulesSection> &_rules)
:
mode(_mode),
practice_id(_practice_id),
name(_name),
rules(_rules)
{
bool any = asset_name == "Any" && url == "Any" && uri == "Any";
string asset_id = any ? "Any" : url+uri;
context = "assetId(" + asset_id + ")";
}
void
RateLimitSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("mode", key_to_mode_val.at(mode)),
cereal::make_nvp("practiceId", practice_id),
cereal::make_nvp("name", name),
cereal::make_nvp("rules", rules)
);
}
const string &
RateLimitSection::getId() const
{
return practice_id;
}
const string &
RateLimitSection::getName() const
{
return name;
}
const string &
RateLimitSection::getMode() const
{
return mode;
}
void
AccessControlRulebaseSection::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> empty;
out_ar(
cereal::make_nvp("accessControl", empty),
cereal::make_nvp("traditionalFirewall", empty),
cereal::make_nvp("l4firewall", empty),
cereal::make_nvp("rateLimit", rate_limit)
);
}
void
AccessControlRulebaseWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", rule_base)
);
}
void
AccessControlRateLimiteRules::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limite rules";
parseAppsecJSONKey<int>("limit", limit, archive_in);
parseAppsecJSONKey<string>("uri", uri, archive_in);
parseAppsecJSONKey<string>("unit", unit, archive_in);
if (valid_units.count(unit) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "Access control rate limite rules units invalid: "
<< unit;
}
parseAppsecJSONKey<string>("comment", comment, archive_in);
parseAppsecJSONKey<vector<string>>("triggers", triggers, archive_in);
}
const vector<string>
AccessControlRateLimiteRules::getTriggers() const
{
return triggers;
}
RateLimitRulesSection
AccessControlRateLimiteRules::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const
{
string id = "";
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to create random id";
}
vector<RateLimitRulesTriggerSection> triggers_section;
string trigger_name = trigger.getName().substr(trigger.getName().find("/") + 1);
if (find(triggers.begin(), triggers.end(), trigger_name) != triggers.end()) {
triggers_section.push_back(trigger);
}
return RateLimitRulesSection(
limit,
id,
uri,
unit,
triggers_section
);
}
void
AccessControlRateLimit::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limit";
parseAppsecJSONKey<string>("overrideMode", mode, archive_in, "Inactive");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << mode;
}
parseAppsecJSONKey<std::vector<AccessControlRateLimiteRules>>("rules", rules, archive_in);
}
vector<RateLimitRulesSection>
AccessControlRateLimit::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const
{
vector<RateLimitRulesSection> rules_section;
for (const AccessControlRateLimiteRules &rule : rules) {
rules_section.push_back(rule.createRateLimitRulesSection(trigger));
}
return rules_section;
}
const vector<AccessControlRateLimiteRules> &
AccessControlRateLimit::getRules() const
{
return rules;
}
const string &
AccessControlRateLimit::getMode() const
{
return mode;
}
void
AccessControlPracticeSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec";
parseAppsecJSONKey<string>("name", practice_name, archive_in);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<AccessControlRateLimit>("rateLimit", rate_limit, archive_in);
}
void
AccessControlPracticeSpec::setName(const string &_name)
{
practice_name = _name;
}
const AccessControlRateLimit &
AccessControlPracticeSpec::geRateLimit() const
{
return rate_limit;
}
const string &
AccessControlPracticeSpec::getAppSecClassName() const
{
return appsec_class_name;
}
const string &
AccessControlPracticeSpec::getName() const
{
return practice_name;
}
// LCOV_EXCL_STOP

View File

@@ -34,6 +34,26 @@ AppSecWebBotsURI::getURI() const
return uri;
}
vector<string>
AppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const AppSecWebBotsURI &uri : injected_uris) {
injected.push_back(uri.getURI());
}
return injected;
}
vector<string>
AppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> validated;
for (const AppSecWebBotsURI &uri : validated_uris) {
validated.push_back(uri.getURI());
}
return validated;
}
void
AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in)
{
@@ -52,7 +72,7 @@ AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const
vector<string> injected;
vector<string> validated;
for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
out_ar(
cereal::make_nvp("injected", injected),
cereal::make_nvp("validated", validated)
@@ -295,24 +315,90 @@ 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)
{
string source_ident = parsed_trusted_sources.getSourceIdent();
map<string, string> behavior = {{"httpSourceId", source_ident}};
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
AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const
{
string parameter_type = "TrustedSource";
if (!id.empty()) {
out_ar(cereal::make_nvp("id", id));
}
out_ar(
cereal::make_nvp("parsedBehavior", parsed_behavior),
cereal::make_nvp("parsedMatch", parsed_match)
);
}
void
AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("injected", injected_uris),
cereal::make_nvp("validated", validated_uris)
);
}
// LCOV_EXCL_START Reason: no test exist
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
@@ -321,10 +407,12 @@ WebAppSection::WebAppSection(
const string &_rule_name,
const string &_practice_id,
const string &_practice_name,
const string &_context,
const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger,
const string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources)
const AppSecTrustedSources &parsed_trusted_sources,
const vector<InnerException> &parsed_exceptions)
:
application_urls(_application_urls),
asset_id(_asset_id),
@@ -333,7 +421,7 @@ WebAppSection::WebAppSection(
rule_name(_rule_name),
practice_id(_practice_id),
practice_name(_practice_name),
context("practiceId(" + practice_id +")"),
context(_context),
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
practice_advanced_config(parsed_appsec_spec),
@@ -351,8 +439,56 @@ WebAppSection::WebAppSection(
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident));
}
for (const InnerException &exception : parsed_exceptions) {
overrides.push_back(AppSecOverride(exception));
}
}
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
const string &_asset_name,
const string &_rule_id,
const string &_rule_name,
const string &_practice_id,
const string &_practice_name,
const string &_context,
const string &_web_attack_mitigation_severity,
const string &_web_attack_mitigation_mode,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
const AppSecTrustedSources &parsed_trusted_sources)
:
application_urls(_application_urls),
asset_id(_asset_id),
asset_name(_asset_name),
rule_id(_rule_id),
rule_name(_rule_name),
practice_id(_practice_id),
practice_name(_practice_name),
context(_context),
web_attack_mitigation_severity(_web_attack_mitigation_severity),
web_attack_mitigation_mode(_web_attack_mitigation_mode),
practice_advanced_config(_practice_advanced_config),
anti_bots(_anti_bots),
trusted_sources({parsed_trusted_sources})
{
web_attack_mitigation = true;
web_attack_mitigation_action =
web_attack_mitigation_severity == "critical" ? "low" :
web_attack_mitigation_severity == "high" ? "balanced" :
web_attack_mitigation_severity == "medium" ? "high" :
"Error";
triggers.push_back(TriggersInWaapSection(parsed_log_trigger));
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident));
}
}
// LCOV_EXCL_STOP
void
WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -536,7 +672,7 @@ AppsecPolicySpec::getSpecificRules() const
}
bool
AppsecPolicySpec::isAssetHostExist(const std::string &full_url) const
AppsecPolicySpec::isAssetHostExist(const string &full_url) const
{
for (const ParsedRule &rule : specific_rules) {
if (rule.getHost() == full_url) return true;
@@ -558,7 +694,7 @@ AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
parseAppsecJSONKey<vector<AppSecPracticeSpec>>("practices", practices, archive_in);
parseAppsecJSONKey<vector<AppsecTriggerSpec>>("log-triggers", log_triggers, 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<SourceIdentifierSpecWrapper>>(
"source-identifiers",
@@ -591,8 +727,8 @@ AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
return custom_responses;
}
const vector<AppsecExceptionSpec> &
AppsecLinuxPolicy::getAppsecExceptionSpecs() const
const vector<AppsecException> &
AppsecLinuxPolicy::getAppsecExceptions() const
{
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);
// 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 unordered_map<string, string> key_to_action = {
{ "accept", "accept"},
{ "drop", "reject"},
{ "skip", "ignore"},
{ "suppressLog", "ignore"}
};
void
AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception spec";
parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in, "skip");
if (valid_actions.count(action) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action;
}
parseAppsecJSONKey<vector<string>>("countryCode", country_code, archive_in);
if (!country_code.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("countryName", country_name, archive_in);
if (!country_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("hostName", host_name, archive_in);
if (!host_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramName", param_name, archive_in);
if (!param_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramValue", param_value, archive_in);
if (!param_value.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("protectionName", protection_name, archive_in);
if (!protection_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIdentifier", source_identifier, archive_in);
if (!source_identifier.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIp", source_ip, archive_in);
if (!source_ip.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("url", url, archive_in);
}
void
AppsecExceptionSpec::setName(const string &_name)
{
name = _name;
}
const string &
AppsecExceptionSpec::getName() const
{
return name;
if (!url.empty()) conditions_number++;
}
const string &
@@ -113,10 +135,89 @@ AppsecExceptionSpec::getUrl() const
return url;
}
bool
AppsecExceptionSpec::isOneCondition() const
{
return conditions_number == 1;
}
void
AppsecException::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception";
parseAppsecJSONKey<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)
:
match_type(MatchType::Operator),
op("and")
{
bool single_condition = parsed_exception.isOneCondition();
for (auto &attrib : attributes) {
auto &attrib_name = attrib.first;
auto &attrib_getter = attrib.second;
auto exceptions_value = attrib_getter(parsed_exception);
if (exceptions_value.empty()) continue;
if (single_condition) {
if (exceptions_value.size() == 1) {
match_type = MatchType::Condition;
op = "equals";
key = attrib_name;
value = exceptions_value;
return;
} else {
match_type = MatchType::Operator;
op = "or";
for (auto new_value : exceptions_value) {
items.push_back(ExceptionMatch(attrib_name, {new_value}));
}
return;
}
}
items.push_back(ExceptionMatch(attrib_name, exceptions_value));
}
}
ExceptionMatch::ExceptionMatch(const std::string &_key, const std::vector<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}));
}
}
}
ExceptionMatch::ExceptionMatch(const NewAppsecException &parsed_exception)
:
match_type(MatchType::Operator),
op("and")
{
if (!parsed_exception.getCountryCode().empty()) {
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode()));
@@ -176,13 +277,34 @@ ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const
}
}
ExceptionBehavior::ExceptionBehavior(
const string &_key,
const string &_value)
:
key(_key),
value(_value)
const string &
ExceptionMatch::getOperator() const
{
return op;
}
const string &
ExceptionMatch::getKey() const
{
return key;
}
const string &
ExceptionMatch::getValue() const
{
return value[0];
}
const vector<ExceptionMatch> &
ExceptionMatch::getMatch() const
{
return items;
}
ExceptionBehavior::ExceptionBehavior(const string &_value)
{
key = _value == "suppressLog" ? "log" : "action";
value = key_to_action.at(_value);
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
@@ -200,12 +322,31 @@ ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const
);
}
const string
const string &
ExceptionBehavior::getBehaviorId() const
{
return id;
}
const string &
ExceptionBehavior::getBehaviorKey() const
{
return key;
}
const string &
ExceptionBehavior::getBehaviorValue() const
{
return value;
}
InnerException::InnerException(ExceptionBehavior _behavior, ExceptionMatch _match)
:
behavior(_behavior),
match(_match)
{
}
void
InnerException::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -215,12 +356,30 @@ InnerException::save(cereal::JSONOutputArchive &out_ar) const
);
}
const string
const string &
InnerException::getBehaviorId() const
{
return behavior.getBehaviorId();
}
const string &
InnerException::getBehaviorKey() const
{
return behavior.getBehaviorKey();
}
const string &
InnerException::getBehaviorValue() const
{
return behavior.getBehaviorValue();
}
const ExceptionMatch &
InnerException::getMatch() const
{
return match;
}
ExceptionsRulebase::ExceptionsRulebase(
vector<InnerException> _exceptions)
:

View File

@@ -0,0 +1,192 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ACCESS_CONTROL_PRACTICE_H__
#define __ACCESS_CONTROL_PRACTICE_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
class RateLimitRulesTriggerSection
{
public:
// LCOV_EXCL_START Reason: no test exist
RateLimitRulesTriggerSection() {};
RateLimitRulesTriggerSection(
const std::string &_id,
const std::string &_name,
const std::string &_type
)
:
id(_id),
name(_name),
type(_type)
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getName() const;
private:
std::string id;
std::string name;
std::string type;;
};
class RateLimitRulesSection
{
public:
RateLimitRulesSection() {};
// LCOV_EXCL_START Reason: no test exist
RateLimitRulesSection(
const int _limit,
const std::string &_id,
const std::string &_uri,
const std::string &_scope,
const std::vector<RateLimitRulesTriggerSection> &_triggers
)
:
limit(_limit),
id(_id),
uri(_uri),
scope(_scope),
triggers(_triggers)
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
int limit;
std::string id;
std::string uri;
std::string scope;
std::vector<RateLimitRulesTriggerSection> triggers;
};
class RateLimitSection
{
public:
// LCOV_EXCL_START Reason: no test exist
RateLimitSection() {};
// LCOV_EXCL_STOP
RateLimitSection(
const std::string &asset_name,
const std::string &url,
const std::string &uri,
const std::string &_mode,
const std::string &_practice_id,
const std::string &_name,
const std::vector<RateLimitRulesSection> &_rules);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getId() const;
const std::string & getName() const;
const std::string & getMode() const;
private:
std::string context;
std::string mode;
std::string practice_id;
std::string name;
std::vector<RateLimitRulesSection> rules;
};
class AccessControlRulebaseSection
{
public:
AccessControlRulebaseSection() {};
AccessControlRulebaseSection(const std::vector<RateLimitSection> &_rate_limit) : rate_limit(_rate_limit) {};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<RateLimitSection> rate_limit;
};
class AccessControlRulebaseWrapper
{
public:
AccessControlRulebaseWrapper() {};
AccessControlRulebaseWrapper(
const std::vector<RateLimitSection> &rate_limits
)
:
rule_base(AccessControlRulebaseSection(rate_limits))
{};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
AccessControlRulebaseSection rule_base;
};
class AccessControlRateLimiteRules
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<std::string> getTriggers() const;
RateLimitRulesSection createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
int limit;
std::string uri;
std::string unit;
std::string comment;
std::vector<std::string> triggers;
};
class AccessControlRateLimit
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<AccessControlRateLimiteRules> & getRules() const;
const std::string & getMode() const;
std::vector<RateLimitRulesSection> createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
std::string mode;
std::vector<AccessControlRateLimiteRules> rules;
};
class AccessControlPracticeSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
const AccessControlRateLimit & geRateLimit() const;
const std::string & getAppSecClassName() const;
const std::string & getName() const;
void setName(const std::string &_name);
private:
AccessControlRateLimit rate_limit;
std::string appsec_class_name;
std::string practice_name;
};
#endif // __ACCESS_CONTROL_PRACTICE_H__

View File

@@ -28,6 +28,7 @@
#include "triggers_section.h"
#include "exceptions_section.h"
#include "trusted_sources_section.h"
#include "new_practice.h"
class AppSecWebBotsURI
{
@@ -43,6 +44,9 @@ private:
class AppSecPracticeAntiBot
{
public:
std::vector<std::string> getIjectedUris() const;
std::vector<std::string> getValidatedUris() const;
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
@@ -152,6 +156,22 @@ public:
url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes())
{}
// LCOV_EXCL_START Reason: no test exist
PracticeAdvancedConfig(
int _http_header_max_size,
int _http_request_body_max_size,
int _json_max_object_depth,
int _url_max_size)
:
http_header_max_size(_http_header_max_size),
http_illegal_methods_allowed(0),
http_request_body_max_size(_http_request_body_max_size),
json_max_object_depth(_json_max_object_depth),
url_max_size(_url_max_size)
{}
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -182,16 +202,58 @@ private:
LogTriggerSection log;
};
class AppSecOverride
class ParsedMatch
{
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;
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::map<std::string, std::string> parsed_match;
ParsedMatch parsed_match;
};
class AppsecPracticeAntiBotSection
{
public:
AppsecPracticeAntiBotSection() {};
// LCOV_EXCL_START Reason: no test exist
AppsecPracticeAntiBotSection(const NewAppSecPracticeAntiBot &anti_bot) :
injected_uris(anti_bot.getIjectedUris()),
validated_uris(anti_bot.getValidatedUris())
{};
// LCOV_EXCL_STOP
AppsecPracticeAntiBotSection(const AppSecPracticeAntiBot &anti_bot) :
injected_uris(anti_bot.getIjectedUris()),
validated_uris(anti_bot.getValidatedUris())
{};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<std::string> injected_uris;
std::vector<std::string> validated_uris;
};
class WebAppSection
@@ -207,12 +269,30 @@ public:
const std::string &_rule_name,
const std::string &_practice_id,
const std::string &_practice_name,
const std::string &_context,
const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources
const AppSecTrustedSources &parsed_trusted_sources,
const std::vector<InnerException> &parsed_exceptions
);
WebAppSection(
const std::string &_application_urls,
const std::string &_asset_id,
const std::string &_asset_name,
const std::string &_rule_id,
const std::string &_rule_name,
const std::string &_practice_id,
const std::string &_practice_name,
const std::string &_context,
const std::string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
const AppSecTrustedSources &parsed_trusted_sources);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -230,7 +310,7 @@ private:
bool web_attack_mitigation;
std::vector<TriggersInWaapSection> triggers;
PracticeAdvancedConfig practice_advanced_config;
AppSecPracticeAntiBot anti_bots;
AppsecPracticeAntiBotSection anti_bots;
std::vector<AppSecTrustedSources> trusted_sources;
std::vector<AppSecOverride> overrides;
};
@@ -250,7 +330,7 @@ public:
const std::string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode,
bool _web_attack_mitigation,
const AppSecPracticeSpec &parsed_appsec_spec)
const PracticeAdvancedConfig &_practice_advanced_config)
:
application_urls(_application_urls),
asset_id(_asset_id),
@@ -264,7 +344,7 @@ public:
web_attack_mitigation_severity(_web_attack_mitigation_severity),
web_attack_mitigation_mode(_web_attack_mitigation_mode),
web_attack_mitigation(_web_attack_mitigation),
practice_advanced_config(parsed_appsec_spec)
practice_advanced_config(_practice_advanced_config)
{}
void save(cereal::JSONOutputArchive &out_ar) const;
@@ -302,6 +382,7 @@ private:
std::vector<WebAPISection> webAPIPractices;
};
class AppSecWrapper
{
public:
@@ -369,7 +450,7 @@ public:
const std::vector<AppSecPracticeSpec> &_practices,
const std::vector<AppsecTriggerSpec> &_log_triggers,
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<SourceIdentifierSpecWrapper> &_sources_identifiers)
:
@@ -387,7 +468,7 @@ public:
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() 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<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
void addSpecificRule(const ParsedRule &_rule);
@@ -397,7 +478,7 @@ private:
std::vector<AppSecPracticeSpec> practices;
std::vector<AppsecTriggerSpec> log_triggers;
std::vector<AppSecCustomResponseSpec> custom_responses;
std::vector<AppsecExceptionSpec> exceptions;
std::vector<AppsecException> exceptions;
std::vector<TrustedSourcesSpec> trusted_sources;
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

@@ -24,13 +24,13 @@
#include "debug.h"
#include "rest.h"
#include "local_policy_common.h"
#include "new_exceptions.h"
class AppsecExceptionSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAction() const;
const std::vector<std::string> & getCountryCode() const;
const std::vector<std::string> & getCountryName() const;
@@ -41,10 +41,10 @@ public:
const std::vector<std::string> & getSourceIdentifier() const;
const std::vector<std::string> & getSourceIp() const;
const std::vector<std::string> & getUrl() const;
void setName(const std::string &_name);
bool isOneCondition() const;
private:
std::string name;
int conditions_number;
std::string action;
std::vector<std::string> country_code;
std::vector<std::string> country_name;
@@ -57,20 +57,42 @@ private:
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
{
public:
ExceptionMatch() {}
ExceptionMatch(const AppsecExceptionSpec &parsed_exception);
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
:
match_type(MatchType::Condition),
key(_key),
op("in"),
value(_value)
{}
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value);
ExceptionMatch(const NewAppsecException &parsed_exception);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getOperator() const;
const std::string & getKey() const;
const std::string & getValue() const;
const std::vector<ExceptionMatch> & getMatch() const;
private:
MatchType match_type;
@@ -84,13 +106,12 @@ class ExceptionBehavior
{
public:
ExceptionBehavior() {}
ExceptionBehavior(
const std::string &_key,
const std::string &_value
);
ExceptionBehavior(const std::string &_value);
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:
std::string key;
@@ -102,15 +123,13 @@ class InnerException
{
public:
InnerException() {}
InnerException(
ExceptionBehavior _behavior,
ExceptionMatch _match)
:
behavior(_behavior),
match(_match) {}
InnerException(ExceptionBehavior _behavior, ExceptionMatch _match);
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:
ExceptionBehavior behavior;

View File

@@ -28,6 +28,7 @@
#include "i_env_details.h"
#include "i_agent_details.h"
#include "appsec_practice_section.h"
#include "new_appsec_linux_policy.h"
#include "policy_maker_utils.h"
enum class AnnotationKeys { PolicyKey, OpenAppsecIo, SyslogAddressKey, SyslogPortKey, ModeKey };
@@ -44,8 +45,9 @@ class K8sPolicyUtils
public:
void init();
std::map<std::string, AppsecLinuxPolicy> createAppsecPoliciesFromIngresses();
bool getClusterId() const;
std::tuple<std::map<std::string, AppsecLinuxPolicy>, std::map<std::string, V1beta2AppsecLinuxPolicy>>
createAppsecPoliciesFromIngresses();
void getClusterId() const;
private:
std::map<AnnotationKeys, std::string> parseIngressAnnotations(
@@ -60,13 +62,48 @@ private:
const ParsedRule &default_rule
) const;
std::map<AnnotationTypes, std::unordered_set<std::string>> extractElementsNamesV1beta2(
const std::vector<NewParsedRule> &specific_rules,
const NewParsedRule &default_rule
) const;
std::vector<AppsecException> extractExceptionsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
template<class T>
std::vector<T> extractElementsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
Maybe<AppsecLinuxPolicy> createAppsecPolicyK8s(
void createSnortFile(std::vector<NewAppSecPracticeSpec> &practices) const;
template<class T>
std::vector<T> extractV1Beta2ElementsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
Maybe<AppsecLinuxPolicy> createAppsecPolicyK8sFromV1beta1Crds(
const AppsecSpecParser<AppsecPolicySpec> &appsec_policy_spe,
const std::string &ingress_mode
) const;
Maybe<V1beta2AppsecLinuxPolicy> createAppsecPolicyK8sFromV1beta2Crds(
const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spe,
const std::string &ingress_mode
) const;
template<class T, class K>
void createPolicy(
T &appsec_policy,
std::map<std::string, T> &policies,
std::map<AnnotationKeys, std::string> &annotations_values,
const SingleIngressData &item) const;
std::tuple<Maybe<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>> createAppsecPolicyK8s(
const std::string &policy_name,
const std::string &ingress_mode
) const;

View File

@@ -22,10 +22,13 @@
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#include "customized_cereal_map.h"
USE_DEBUG_FLAG(D_LOCAL_POLICY);
enum class PracticeType { WebApplication, WebAPI };
enum class PracticeType { WebApplication, WebAPI, RateLimit };
enum class TriggerType { Log, WebUserResponse };
enum class MatchType { Condition, Operator };
@@ -36,7 +39,8 @@ static const std::unordered_map<std::string, MatchType> string_to_match_type = {
static const std::unordered_map<std::string, PracticeType> string_to_practice_type = {
{ "WebApplication", PracticeType::WebApplication },
{ "WebAPI", PracticeType::WebAPI }
{ "WebAPI", PracticeType::WebAPI },
{ "RateLimit", PracticeType::RateLimit }
};
static const std::unordered_map<std::string, TriggerType> string_to_trigger_type = {
@@ -73,6 +77,26 @@ parseAppsecJSONKey(
}
}
class AppsecSpecParserMetaData
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "AppsecSpecParserMetaData load";
parseAppsecJSONKey<std::map<std::string, std::string>>("annotations", annotations, archive_in);
}
const std::map<std::string, std::string> &
getAnnotations() const
{
return annotations;
}
private:
std::map<std::string, std::string> annotations;
};
template <typename T>
class AppsecSpecParser : public ClientRest
{
@@ -90,6 +114,7 @@ public:
try {
cereal::JSONInputArchive in_ar(ss);
in_ar(cereal::make_nvp("spec", spec));
in_ar(cereal::make_nvp("metadata", meta_data));
} catch (cereal::Exception &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to load spec JSON. Error: " << e.what();
return false;
@@ -103,10 +128,17 @@ public:
spec.setName(_name);
}
const AppsecSpecParserMetaData &
getMetaData() const
{
return meta_data;
}
const T & getSpec() const { return spec; }
private:
T spec;
AppsecSpecParserMetaData meta_data;
};
#endif // __LOCAL_POLICY_COMMON_H__

View File

@@ -0,0 +1,84 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_APPSEC_LINUX_POLICY_H__
#define __NEW_APPSEC_LINUX_POLICY_H__
#include <list>
#include <vector>
#include <cereal/archives/json.hpp>
#include <cereal/types/list.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "customized_cereal_map.h"
#include "new_appsec_policy_crd_parser.h"
#include "new_custom_response.h"
#include "new_exceptions.h"
#include "new_log_trigger.h"
#include "new_practice.h"
#include "access_control_practice.h"
#include "new_trusted_sources.h"
class V1beta2AppsecLinuxPolicy : Singleton::Consume<I_Environment>
{
public:
// LCOV_EXCL_START Reason: no test exist
V1beta2AppsecLinuxPolicy() {}
V1beta2AppsecLinuxPolicy(
const NewAppsecPolicySpec &_policies,
const std::vector<NewAppSecPracticeSpec> &_threat_prevention_practices,
const std::vector<AccessControlPracticeSpec> &_access_control_practices,
const std::vector<NewAppsecLogTrigger> &_log_triggers,
const std::vector<NewAppSecCustomResponse> &_custom_responses,
const std::vector<NewAppsecException> &_exceptions,
const std::vector<NewTrustedSourcesSpec> &_trusted_sources,
const std::vector<NewSourcesIdentifiers> &_sources_identifiers)
:
policies(_policies),
threat_prevection_practices(_threat_prevention_practices),
access_control_practices(_access_control_practices),
log_triggers(_log_triggers),
custom_responses(_custom_responses),
exceptions(_exceptions),
trusted_sources(_trusted_sources),
sources_identifiers(_sources_identifiers) {}
// LCOV_EXCL_STOP
const NewAppsecPolicySpec & getAppsecPolicySpec() const;
const std::vector<NewAppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AccessControlPracticeSpec> & getAccessControlPracticeSpecs() const;
const std::vector<NewAppsecLogTrigger> & getAppsecTriggerSpecs() const;
const std::vector<NewAppSecCustomResponse> & getAppSecCustomResponseSpecs() const;
const std::vector<NewAppsecException> & getAppsecExceptions() const;
const std::vector<NewTrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<NewSourcesIdentifiers> & getAppsecSourceIdentifierSpecs() const;
void addSpecificRule(const NewParsedRule &_rule);
private:
NewAppsecPolicySpec policies;
std::vector<NewAppSecPracticeSpec> threat_prevection_practices;
std::vector<AccessControlPracticeSpec> access_control_practices;
std::vector<NewAppsecLogTrigger> log_triggers;
std::vector<NewAppSecCustomResponse> custom_responses;
std::vector<NewAppsecException> exceptions;
std::vector<NewTrustedSourcesSpec> trusted_sources;
std::vector<NewSourcesIdentifiers> sources_identifiers;
};
#endif // __NEW_APPSEC_LINUX_POLICY_H__

View File

@@ -0,0 +1,82 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_APPSEC_POLICY_CRD_PARSER_H__
#define __NEW_APPSEC_POLICY_CRD_PARSER_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "local_policy_common.h"
// LCOV_EXCL_START Reason: no test exist
class NewParsedRule
{
public:
NewParsedRule() {}
NewParsedRule(const std::string &_host) : host(_host) {}
void load(cereal::JSONInputArchive &archive_in);
const std::vector<std::string> & getLogTriggers() const;
const std::vector<std::string> & getExceptions() const;
const std::vector<std::string> & getPractices() const;
const std::vector<std::string> & getAccessControlPractices() const;
const std::string & getSourceIdentifiers() const;
const std::string & getCustomResponse() const;
const std::string & getTrustedSources() const;
const std::string & getHost() const;
const std::string & getMode() const;
void setHost(const std::string &_host);
void setMode(const std::string &_mode);
private:
std::vector<std::string> log_triggers;
std::vector<std::string> exceptions;
std::vector<std::string> threat_prevention_practices;
std::vector<std::string> access_control_practices;
std::string source_identifiers;
std::string custom_response;
std::string trusted_sources;
std::string host;
std::string mode;
};
class NewAppsecPolicySpec : Singleton::Consume<I_Environment>
{
public:
void load(cereal::JSONInputArchive &archive_in);
const NewParsedRule & getDefaultRule() const;
const std::vector<NewParsedRule> & getSpecificRules() const;
const std::string & getAppSecClassName() const;
bool isAssetHostExist(const std::string &full_url) const;
void addSpecificRule(const NewParsedRule &_rule);
private:
std::string appsec_class_name;
NewParsedRule default_rule;
std::vector<NewParsedRule> specific_rules;
};
#endif // __NEW_APPSEC_POLICY_CRD_PARSER_H__
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_CUSTOM_RESPONSE_H__
#define __NEW_CUSTOM_RESPONSE_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
class NewAppSecCustomResponse
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getHttpResponseCode() const;
const std::string & getMessageBody() const;
const std::string & getMessageTitle() const;
const std::string & getAppSecClassName() const;
const std::string & getMode() const;
const std::string & getName() const;
void setName(const std::string &_name);
private:
bool redirect_add_x_event_id;
int http_response_code;
std::string appsec_class_name;
std::string redirect_url;
std::string message_title;
std::string message_body;
std::string mode;
std::string name;
};
#endif // __NEW_CUSTOM_RESPONSE_H__

View File

@@ -0,0 +1,67 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_EXCEPTIONS_H__
#define __NEW_EXCEPTIONS_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "local_policy_common.h"
class NewAppsecExceptionCondition
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getKey() const;
const std::string & getvalue() const;
private:
std::string key;
std::string value;
};
class NewAppsecException
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAction() const;
const std::string & getAppSecClassName() const;
const std::vector<std::string> getCountryCode() const;
const std::vector<std::string> getCountryName() const;
const std::vector<std::string> getHostName() const;
const std::vector<std::string> getParamName() const;
const std::vector<std::string> getParamValue() const;
const std::vector<std::string> getProtectionName() const;
const std::vector<std::string> getSourceIdentifier() const;
const std::vector<std::string> getSourceIp() const;
const std::vector<std::string> getUrl() const;
void setName(const std::string &_name);
private:
std::string appsec_class_name;
std::string name;
std::string action;
std::vector<NewAppsecExceptionCondition> conditions;
};
#endif // __NEW_EXCEPTIONS_H__

View File

@@ -0,0 +1,172 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_LOG_TRIGGERS_H__
#define __NEW_LOG_TRIGGERS_H__
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
#include "i_agent_details.h"
#include "i_env_details.h"
class NewAppsecTriggerAccessControlLogging
{
public:
void load(cereal::JSONInputArchive &archive_in);
private:
bool allow_events = false;
bool drop_events = false;
};
class NewAppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
{
public:
void load(cereal::JSONInputArchive &archive_in);
bool isEnabled() const;
bool isResponseBody() const;
const std::string & getMinimumSeverity() const;
private:
bool enabled = true;
bool response_body = false;
bool response_code = false;
std::string minimum_severity = "high";
};
class NewAppsecTriggerLogging : public ClientRest
{
public:
void
load(cereal::JSONInputArchive &archive_in);
bool isAllWebRequests() const;
bool isDetectEvents() const;
bool isPreventEvents() const;
private:
bool all_web_requests = false;
bool detect_events = false;
bool prevent_events = true;
};
class NewAppsecTriggerExtendedLogging : public ClientRest
{
public:
void load(cereal::JSONInputArchive &archive_in);
bool isHttpHeaders() const;
bool isRequestBody() const;
bool isUrlPath() const;
bool isUrlQuery() const;
private:
bool http_headers = false;
bool request_body = false;
bool url_path = false;
bool url_query = false;
};
class NewLoggingService
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getAddress() const;
int getPort() const;
private:
std::string address;
std::string proto;
int port = 514;
};
class NewStdoutLogging
{
public:
// LCOV_EXCL_START Reason: no test exist
NewStdoutLogging() : format("json") {}
// LCOV_EXCL_STOP
void load(cereal::JSONInputArchive &archive_in);
const std::string & getFormat() const;
private:
std::string format;
};
class NewAppsecTriggerLogDestination
:
public ClientRest,
Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_EnvDetails>
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getCefServerUdpPort() const;
int getSyslogServerUdpPort() const;
bool isAgentLocal() const;
bool shouldBeautifyLogs() const;
bool getCloud() const;
bool isK8SNeeded() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
const std::string & getCefServerIpv4Address() const;
private:
const NewLoggingService & getSyslogServiceData() const;
const NewLoggingService & getCefServiceData() const;
bool cloud = false;
bool k8s_service = false;
bool agent_local = true;
bool beautify_logs = true;
NewLoggingService syslog_service;
NewLoggingService cef_service;
};
class NewAppsecLogTrigger
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAppSecClassName() const;
void setName(const std::string &_name);
const NewAppsecTriggerAdditionalSuspiciousEventsLogging &
getAppsecTriggerAdditionalSuspiciousEventsLogging() const;
const NewAppsecTriggerLogging & getAppsecTriggerLogging() const;
const NewAppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
const NewAppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
private:
NewAppsecTriggerAccessControlLogging access_control_logging;
NewAppsecTriggerAdditionalSuspiciousEventsLogging additional_suspicious_events_logging;
NewAppsecTriggerLogging appsec_logging;
NewAppsecTriggerExtendedLogging extended_logging;
NewAppsecTriggerLogDestination log_destination;
std::string name;
std::string appsec_class_name;
};
#endif // __NEW_LOG_TRIGGERS_H__

View File

@@ -0,0 +1,589 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_PRACTICE_H__
#define __NEW_PRACTICE_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
class IpsProtectionsRulesSection
{
public:
// LCOV_EXCL_START Reason: no test exist
IpsProtectionsRulesSection() {};
IpsProtectionsRulesSection(
const int _protections_from_year,
const std::string &_action,
const std::string &_confidence_level,
const std::string &_performance_impact,
const std::string &_source_identifier,
const std::string &_severity_level
)
:
protections_from_year(_protections_from_year),
action(_action),
confidence_level(_confidence_level),
performance_impact(_performance_impact),
source_identifier(_source_identifier),
severity_level(_severity_level)
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
int protections_from_year;
std::string action;
std::string confidence_level;
std::string performance_impact;
std::string source_identifier;
std::string severity_level;
};
class IpsProtectionsSection
{
public:
// LCOV_EXCL_START Reason: no test exist
IpsProtectionsSection() {};
// LCOV_EXCL_STOP
IpsProtectionsSection(
const std::string &_context,
const std::string &asset_name,
const std::string &_asset_id,
const std::string &_practice_name,
const std::string &_practice_id,
const std::string &_source_identifier,
const std::string &_mode,
const std::vector<IpsProtectionsRulesSection> &_rules);
std::string & getMode();
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string context;
std::string name;
std::string asset_id;
std::string practice_name;
std::string practice_id;
std::string source_identifier;
std::string mode;
std::vector<IpsProtectionsRulesSection> rules;
};
class IPSSection
{
public:
// LCOV_EXCL_START Reason: no test exist
IPSSection() {};
IPSSection(const std::vector<IpsProtectionsSection> &_ips) : ips(_ips) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<IpsProtectionsSection> ips;
};
class IntrusionPreventionWrapper
{
public:
// LCOV_EXCL_START Reason: no test exist
IntrusionPreventionWrapper() {};
IntrusionPreventionWrapper(const std::vector<IpsProtectionsSection> &_ips) : ips(IPSSection(_ips)) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
IPSSection ips;
};
class NewIntrusionPrevention
{
public:
void load(cereal::JSONInputArchive &archive_in);
std::vector<IpsProtectionsRulesSection> createIpsRules() const;
const std::string & getMode() const;
private:
std::string override_mode;
std::string max_performance_impact;
std::string min_severity_level;
std::string high_confidence_event_action;
std::string medium_confidence_event_action;
std::string low_confidence_event_action;
int min_cve_Year;
};
class FileSecurityProtectionsSection
{
public:
// LCOV_EXCL_START Reason: no test exist
FileSecurityProtectionsSection() {};
// LCOV_EXCL_STOP
FileSecurityProtectionsSection(
int _file_size_limit,
int _archive_file_size_limit,
bool _allow_files_without_name,
bool _required_file_size_limit,
bool _required_archive_extraction,
const std::string &_context,
const std::string &_name,
const std::string &_asset_id,
const std::string &_practice_name,
const std::string &_practice_id,
const std::string &_action,
const std::string &_files_without_name_action,
const std::string &_high_confidence_action,
const std::string &_medium_confidence_action,
const std::string &_low_confidence_action,
const std::string &_severity_level,
const std::string &_file_size_limit_action,
const std::string &_multi_level_archive_action,
const std::string &_unopened_archive_action
);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
int file_size_limit;
int archive_file_size_limit;
bool allow_files_without_name;
bool required_file_size_limit;
bool required_archive_extraction;
std::string context;
std::string name;
std::string asset_id;
std::string practice_name;
std::string practice_id;
std::string action;
std::string files_without_name_action;
std::string high_confidence_action;
std::string medium_confidence_action;
std::string low_confidence_action;
std::string severity_level;
std::string file_size_limit_action;
std::string file_size_limit_unit;
std::string scan_max_file_size_unit;
std::string multi_level_archive_action;
std::string unopened_archive_action;
};
class FileSecuritySection
{
public:
// LCOV_EXCL_START Reason: no test exist
FileSecuritySection() {};
FileSecuritySection(const std::vector<FileSecurityProtectionsSection> &_file_security)
:
file_security(_file_security) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<FileSecurityProtectionsSection> file_security;
};
class FileSecurityWrapper
{
public:
// LCOV_EXCL_START Reason: no test exist
FileSecurityWrapper() {};
FileSecurityWrapper(const std::vector<FileSecurityProtectionsSection> &_file_security)
:
file_security(FileSecuritySection(_file_security)) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
FileSecuritySection file_security;
};
class NewFileSecurityArchiveInspection
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getArchiveFileSizeLimit() const;
bool getrequiredArchiveExtraction() const;
const std::string & getMultiLevelArchiveAction() const;
const std::string & getUnopenedArchiveAction() const;
private:
int scan_max_file_size;
bool extract_archive_files;
std::string scan_max_file_size_unit;
std::string archived_files_within_archived_files;
std::string archived_files_where_content_extraction_failed;
};
class NewFileSecurityLargeFileInspection
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getFileSizeLimit() const;
const std::string & getFileSizeLimitAction() const;
private:
int file_size_limit;
std::string file_size_limit_unit;
std::string files_exceeding_size_limit_action;
};
class NewFileSecurity
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getOverrideMode() const;
const NewFileSecurityArchiveInspection & getArchiveInspection() const;
const NewFileSecurityLargeFileInspection & getLargeFileInspection() const;
FileSecurityProtectionsSection createFileSecurityProtectionsSection(
const std::string &context,
const std::string &asset_name,
const std::string &asset_id,
const std::string &practice_name,
const std::string &practice_id
) const;
private:
bool threat_emulation_enabled;
std::string override_mode;
std::string min_severity_level;
std::string high_confidence_event_action;
std::string medium_confidence_event_action;
std::string low_confidence_event_action;
std::string unnamed_files_action;
NewFileSecurityArchiveInspection archive_inspection;
NewFileSecurityLargeFileInspection large_file_inspection;
};
class SnortProtectionsSection
{
public:
// LCOV_EXCL_START Reason: no test exist
SnortProtectionsSection() {};
// LCOV_EXCL_STOP
SnortProtectionsSection(
const std::string &_context,
const std::string &_asset_name,
const std::string &_asset_id,
const std::string &_practice_name,
const std::string &_practice_id,
const std::string &_source_identifier,
const std::string &_mode,
const std::vector<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
{
public:
void load(cereal::JSONInputArchive &archive_in);
void addFile(const std::string &file_name);
const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const;
const std::vector<std::string> & getFiles() const;
private:
std::string override_mode;
std::vector<std::string> config_map;
std::vector<std::string> files;
};
class NewAppSecWebBotsURI
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getURI() const;
private:
std::string uri;
};
class NewAppSecPracticeAntiBot
{
public:
std::vector<std::string> getIjectedUris() const;
std::vector<std::string> getValidatedUris() const;
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string override_mode;
std::vector<NewAppSecWebBotsURI> injected_uris;
std::vector<NewAppSecWebBotsURI> validated_uris;
};
class NewAppSecWebAttackProtections
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string getCsrfProtectionMode() const;
const std::string & getErrorDisclosureMode() const;
bool getNonValidHttpMethods() const;
const std::string getOpenRedirectMode() const;
private:
std::string csrf_protection;
std::string open_redirect;
std::string error_disclosure;
bool non_valid_http_methods;
};
class NewAppSecPracticeWebAttacks
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getMaxBodySizeKb() const;
int getMaxHeaderSizeBytes() const;
int getMaxObjectDepth() const;
int getMaxUrlSizeBytes() const;
const std::string & getMinimumConfidence() const;
const NewAppSecWebAttackProtections & getprotections() const;
const std::string & getMode(const std::string &default_mode = "Inactive") const;
private:
int max_body_size_kb;
int max_header_size_bytes;
int max_object_depth;
int max_url_size_bytes;
std::string mode;
std::string minimum_confidence;
NewAppSecWebAttackProtections protections;
};
class NewAppSecPracticeSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
NewSnortSignaturesAndOpenSchemaAPI & getSnortSignatures();
const NewSnortSignaturesAndOpenSchemaAPI & getOpenSchemaValidation() const;
const NewAppSecPracticeWebAttacks & getWebAttacks() const;
const NewAppSecPracticeAntiBot & getAntiBot() const;
const NewIntrusionPrevention & getIntrusionPrevention() const;
const NewFileSecurity & getFileSecurity() const;
const std::string & getAppSecClassName() const;
const std::string & getName() const;
void setName(const std::string &_name);
private:
NewFileSecurity file_security;
NewIntrusionPrevention intrusion_prevention;
NewSnortSignaturesAndOpenSchemaAPI openapi_schema_validation;
NewSnortSignaturesAndOpenSchemaAPI snort_signatures;
NewAppSecPracticeWebAttacks web_attacks;
NewAppSecPracticeAntiBot anti_bot;
std::string appsec_class_name;
std::string practice_name;
};
#endif // __NEW_PRACTICE_H__

View File

@@ -0,0 +1,74 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NEW_TRUSTED_SOURCES_H__
#define __NEW_TRUSTED_SOURCES_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
class NewTrustedSourcesSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
int getMinNumOfSources() const;
const std::vector<std::string> & getSourcesIdentifiers() const;
const std::string & getAppSecClassName() const;
const std::string & getName() const;
void setName(const std::string &_name);
private:
int min_num_of_sources = 0;
std::string name;
std::vector<std::string> sources_identifiers;
std::string appsec_class_name;
};
class Identifier
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getIdentifier() const;
const std::vector<std::string> & getValues() const;
private:
std::string identifier;
std::vector<std::string> value;
};
class NewSourcesIdentifiers
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAppSecClassName() const;
const std::vector<Identifier> & getSourcesIdentifiers() const;
void setName(const std::string &_name);
private:
std::string name;
std::string appsec_class_name;
std::vector<Identifier> sources_identifiers;
};
#endif // __NEW_TRUSTED_SOURCES_H__

View File

@@ -0,0 +1,266 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __POLICY_MAKER_UTILS_H__
#define __POLICY_MAKER_UTILS_H__
#include <string>
#include <fstream>
#include <utility>
#include <sys/types.h>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "debug.h"
#include "common.h"
#include "maybe_res.h"
#include "i_orchestration_tools.h"
#include "i_shell_cmd.h"
#include "i_messaging.h"
#include "appsec_practice_section.h"
#include "ingress_data.h"
#include "settings_section.h"
#include "triggers_section.h"
#include "local_policy_common.h"
#include "exceptions_section.h"
#include "rules_config_section.h"
#include "trusted_sources_section.h"
#include "new_appsec_linux_policy.h"
#include "access_control_practice.h"
enum class AnnotationTypes {
PRACTICE,
THREAT_PREVENTION_PRACTICE,
ACCESS_CONTROL_PRACTICE,
TRIGGER,
EXCEPTION,
WEB_USER_RES,
SOURCE_IDENTIFIERS,
TRUSTED_SOURCES,
COUNT
};
class SecurityAppsWrapper
{
public:
SecurityAppsWrapper(
const AppSecWrapper &_waap,
const TriggersWrapper &_trrigers,
const RulesConfigWrapper &_rules,
const IntrusionPreventionWrapper &_ips,
const SnortSectionWrapper &_snort,
const AccessControlRulebaseWrapper &_rate_limit,
const FileSecurityWrapper &_file_security,
const ExceptionsWrapper &_exceptions,
const std::string &_policy_version)
:
waap(_waap),
trrigers(_trrigers),
rules(_rules),
ips(_ips),
snort(_snort),
rate_limit(_rate_limit),
file_security(_file_security),
exceptions(_exceptions),
policy_version(_policy_version) {}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
AppSecWrapper waap;
TriggersWrapper trrigers;
RulesConfigWrapper rules;
IntrusionPreventionWrapper ips;
SnortSectionWrapper snort;
AccessControlRulebaseWrapper rate_limit;
FileSecurityWrapper file_security;
ExceptionsWrapper exceptions;
std::string policy_version;
};
class PolicyWrapper
{
public:
PolicyWrapper(
const SettingsWrapper &_settings,
const SecurityAppsWrapper &_security_apps)
:
settings(_settings),
security_apps(_security_apps) {}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
SettingsWrapper settings;
SecurityAppsWrapper security_apps;
};
class PolicyMakerUtils
:
Singleton::Consume<I_Environment>,
Singleton::Consume<I_OrchestrationTools>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_ShellCmd>
{
public:
std::string proccesSingleAppsecPolicy(
const std::string &policy_path,
const std::string &policy_version,
const std::string &local_appsec_policy_path
);
template<class T, class R>
std::string proccesMultipleAppsecPolicies(
const std::map<std::string, T> &appsec_policies,
const std::string &policy_version,
const std::string &local_appsec_policy_path
);
private:
std::string getPolicyName(const std::string &policy_path);
template<class T>
Maybe<T> openFileAsJson(const std::string &path);
void clearElementsMaps();
bool startsWith(const std::string &str, const std::string &prefix);
bool endsWith(const std::string &str, const std::string &suffix);
std::tuple<std::string, std::string, std::string> splitHostName(const std::string &host_name);
std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path);
PolicyWrapper combineElementsToPolicy(const std::string &policy_version);
void
createIpsSections(
const std::string &asset_id,
const std::string &asset_name,
const std::string &practice_id,
const std::string &practice_name,
const std::string &source_identifier,
const std::string & context,
const V1beta2AppsecLinuxPolicy &policy,
std::map<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
createFileSecuritySections(
const std::string &asset_id,
const std::string &asset_name,
const std::string &practice_id,
const std::string &practice_name,
const std::string & context,
const V1beta2AppsecLinuxPolicy &policy,
std::map<AnnotationTypes, std::string> &rule_annotations
);
void
createRateLimitSection(
const std::string &asset_name,
const std::string &url,
const std::string &uri,
const std::string &trigger_id,
const V1beta2AppsecLinuxPolicy &policy,
std::map<AnnotationTypes, std::string> &rule_annotations
);
void createWebAppSection(
const V1beta2AppsecLinuxPolicy &policy,
const RulesConfigRulebase& rule_config,
const std::string &practice_id, const std::string &full_url,
const std::string &default_mode,
std::map<AnnotationTypes, std::string> &rule_annotations
);
void
createThreatPreventionPracticeSections(
const std::string &asset_name,
const std::string &url,
const std::string &uri,
const std::string &default_mode,
const V1beta2AppsecLinuxPolicy &policy,
std::map<AnnotationTypes, std::string> &rule_annotations
);
template<class T, class R>
void createPolicyElementsByRule(
const R &rule,
const R &default_rule,
const T &policy,
const std::string &policy_name
);
template<class T, class R>
void createPolicyElements(
const std::vector<R> &rules,
const R &default_rule,
const T &policy,
const std::string &policy_name
);
template<class T, class R>
void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const T &appsec_policy);
std::map<std::string, LogTriggerSection> log_triggers;
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
std::map<std::string, std::vector<InnerException>> inner_exceptions;
std::map<std::string, WebAppSection> web_apps;
std::map<std::string, RulesConfigRulebase> rules_config;
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, RateLimitSection> rate_limit;
std::map<std::string, UsersIdentifiersRulebase> users_identifiers;
std::map<std::string, AppSecTrustedSources> trusted_sources;
};
template<class T, class R>
std::string
PolicyMakerUtils::proccesMultipleAppsecPolicies(
const std::map<std::string, T> &appsec_policies,
const std::string &policy_version,
const std::string &local_appsec_policy_path)
{
for (const auto &appsec_policy : appsec_policies) {
createAgentPolicyFromAppsecPolicy<T, R>(appsec_policy.first, appsec_policy.second);
}
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
return dumpPolicyToFile(
policy_wrapper,
local_appsec_policy_path
);
}
#endif // __POLICY_MAKER_UTILS_H__

View File

@@ -121,6 +121,8 @@ public:
std::vector<std::string> _identifier_values
);
const std::string & getIdentifier() const;
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -141,6 +143,8 @@ public:
const std::vector<UsersIdentifier> &_source_identifiers
);
const std::string & getIdentifier() const;
void save(cereal::JSONOutputArchive &out_ar) const;
private:

View File

@@ -0,0 +1,587 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "k8s_policy_utils.h"
#include "configmaps.h"
using namespace std;
USE_DEBUG_FLAG(D_NGINX_POLICY);
string
convertAnnotationKeysTostring(const AnnotationKeys &key)
{
switch (key) {
case AnnotationKeys::PolicyKey:
return "policy";
case AnnotationKeys::OpenAppsecIo:
return "openappsec.io/";
case AnnotationKeys::SyslogAddressKey:
return "syslog";
case AnnotationKeys::ModeKey:
return "mode";
default:
return "Irrelevant key";
}
}
void
K8sPolicyUtils::init()
{
env_details = Singleton::Consume<I_EnvDetails>::by<K8sPolicyUtils>();
env_type = env_details->getEnvType();
if (env_type == EnvType::K8S) {
token = env_details->getToken();
messaging = Singleton::Consume<I_Messaging>::by<K8sPolicyUtils>();
conn_flags.setFlag(MessageConnConfig::SECURE_CONN);
conn_flags.setFlag(MessageConnConfig::IGNORE_SSL_VALIDATION);
}
}
map<AnnotationKeys, string>
K8sPolicyUtils::parseIngressAnnotations(const map<string, string> &annotations) const
{
map<AnnotationKeys, string> annotations_values;
for (const auto &annotation : annotations) {
string annotation_key = annotation.first;
string annotation_val = annotation.second;
if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::OpenAppsecIo)) != string::npos) {
if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::PolicyKey)) != string::npos) {
annotations_values[AnnotationKeys::PolicyKey] = annotation_val;
} else if (
annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::SyslogAddressKey)) != string::npos
) {
bool has_port = annotation_val.find(":");
annotations_values[AnnotationKeys::SyslogAddressKey] =
annotation_val.substr(0, annotation_val.find(":"));
annotations_values[AnnotationKeys::SyslogPortKey] =
has_port ? annotation_val.substr(annotation_val.find(":") + 1) : "";
} else if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::ModeKey)) != string::npos) {
annotations_values[AnnotationKeys::ModeKey] = annotation_val;
}
}
}
return annotations_values;
}
template<class T>
Maybe<T, string>
K8sPolicyUtils::getObjectFromCluster(const string &path) const
{
T object;
bool res = messaging->sendObject(
object,
I_Messaging::Method::GET,
"kubernetes.default.svc",
443,
conn_flags,
path,
"Authorization: Bearer " + token + "\nConnection: close"
);
if (res) return object;
return genError(string("Was not able to get object form k8s cluser in path: " + path));
}
map<AnnotationTypes, unordered_set<string>>
K8sPolicyUtils::extractElementsNames(const vector<ParsedRule> &specific_rules, const ParsedRule &default_rule) const
{
map<AnnotationTypes, unordered_set<string>> policy_elements_names;
for (const ParsedRule &specific_rule : specific_rules) {
policy_elements_names[AnnotationTypes::EXCEPTION].insert(
specific_rule.getExceptions().begin(),
specific_rule.getExceptions().end()
);
policy_elements_names[AnnotationTypes::PRACTICE].insert(
specific_rule.getPractices().begin(),
specific_rule.getPractices().end()
);
policy_elements_names[AnnotationTypes::TRIGGER].insert(
specific_rule.getLogTriggers().begin(),
specific_rule.getLogTriggers().end()
);
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(specific_rule.getCustomResponse());
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(specific_rule.getSourceIdentifiers());
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(specific_rule.getTrustedSources());
}
policy_elements_names[AnnotationTypes::EXCEPTION].insert(
default_rule.getExceptions().begin(),
default_rule.getExceptions().end()
);
policy_elements_names[AnnotationTypes::PRACTICE].insert(
default_rule.getPractices().begin(),
default_rule.getPractices().end()
);
policy_elements_names[AnnotationTypes::TRIGGER].insert(
default_rule.getLogTriggers().begin(),
default_rule.getLogTriggers().end()
);
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(default_rule.getCustomResponse());
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(default_rule.getSourceIdentifiers());
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(default_rule.getTrustedSources());
return policy_elements_names;
}
// LCOV_EXCL_START Reason: no test exist
void
extractElementsFromNewRule(
const NewParsedRule &rule,
map<AnnotationTypes, unordered_set<string>> &policy_elements_names)
{
policy_elements_names[AnnotationTypes::EXCEPTION].insert(
rule.getExceptions().begin(),
rule.getExceptions().end()
);
policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE].insert(
rule.getPractices().begin(),
rule.getPractices().end()
);
policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE].insert(
rule.getAccessControlPractices().begin(),
rule.getAccessControlPractices().end()
);
policy_elements_names[AnnotationTypes::TRIGGER].insert(
rule.getLogTriggers().begin(),
rule.getLogTriggers().end()
);
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(rule.getCustomResponse());
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(rule.getSourceIdentifiers());
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(rule.getTrustedSources());
}
map<AnnotationTypes, unordered_set<string>>
K8sPolicyUtils::extractElementsNamesV1beta2(
const vector<NewParsedRule> &specific_rules,
const NewParsedRule &default_rule) const
{
map<AnnotationTypes, unordered_set<string>> policy_elements_names;
for (const NewParsedRule &specific_rule : specific_rules) {
extractElementsFromNewRule(specific_rule, policy_elements_names);
}
extractElementsFromNewRule(default_rule, policy_elements_names);
return policy_elements_names;
}
string
getAppSecClassNameFromCluster()
{
auto env_res = getenv("appsecClassName");
if (env_res != nullptr) return env_res;
return "";
}
// LCOV_EXCL_STOP
vector<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>
vector<T>
K8sPolicyUtils::extractElementsFromCluster(
const string &crd_plural,
const unordered_set<string> &elements_names) const
{
dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural;
vector<T> elements;
for (const string &element_name : elements_names) {
dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name;
auto maybe_appsec_element = getObjectFromCluster<AppsecSpecParser<T>>(
"/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<T> appsec_element = maybe_appsec_element.unpack();
if (appsec_element.getSpec().getName() == "") {
appsec_element.setName(element_name);
}
elements.push_back(appsec_element.getSpec());
}
return elements;
}
// LCOV_EXCL_START Reason: no test exist
template<class T>
vector<T>
K8sPolicyUtils::extractV1Beta2ElementsFromCluster(
const string &crd_plural,
const unordered_set<string> &elements_names) const
{
dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural;
vector<T> elements;
for (const string &element_name : elements_names) {
dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name;
auto maybe_appsec_element = getObjectFromCluster<AppsecSpecParser<T>>(
"/apis/openappsec.io/v1beta2/" + crd_plural + "/" + element_name
);
if (!maybe_appsec_element.ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve AppSec element. type: "
<< crd_plural
<< ", name: "
<< element_name
<< ". Error: "
<< maybe_appsec_element.getErr();
continue;
}
AppsecSpecParser<T> appsec_element = maybe_appsec_element.unpack();
if (getAppSecClassNameFromCluster() != "" &&
appsec_element.getSpec().getAppSecClassName() != getAppSecClassNameFromCluster()) {
continue;
}
if (appsec_element.getSpec().getName() == "") {
appsec_element.setName(element_name);
}
elements.push_back(appsec_element.getSpec());
}
return elements;
}
// LCOV_EXCL_STOP
Maybe<AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds(
const AppsecSpecParser<AppsecPolicySpec> &appsec_policy_spec,
const string &ingress_mode) const
{
ParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule();
vector<ParsedRule> specific_rules = appsec_policy_spec.getSpec().getSpecificRules();
if (!ingress_mode.empty() && default_rule.getMode().empty()) {
default_rule.setMode(ingress_mode);
}
map<AnnotationTypes, unordered_set<string>> policy_elements_names = extractElementsNames(
specific_rules,
default_rule
);
vector<AppSecPracticeSpec> practices = extractElementsFromCluster<AppSecPracticeSpec>(
"practices",
policy_elements_names[AnnotationTypes::PRACTICE]
);
vector<AppsecTriggerSpec> log_triggers = extractElementsFromCluster<AppsecTriggerSpec>(
"logtriggers",
policy_elements_names[AnnotationTypes::TRIGGER]
);
vector<AppSecCustomResponseSpec> web_user_responses = extractElementsFromCluster<AppSecCustomResponseSpec>(
"customresponses",
policy_elements_names[AnnotationTypes::WEB_USER_RES]
);
vector<AppsecException> exceptions = extractExceptionsFromCluster(
"exceptions",
policy_elements_names[AnnotationTypes::EXCEPTION]
);
vector<SourceIdentifierSpecWrapper> source_identifiers = extractElementsFromCluster<SourceIdentifierSpecWrapper>(
"sourcesidentifiers",
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS]
);
vector<TrustedSourcesSpec> trusted_sources = extractElementsFromCluster<TrustedSourcesSpec>(
"trustedsources",
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES]
);
AppsecLinuxPolicy appsec_policy = AppsecLinuxPolicy(
appsec_policy_spec.getSpec(),
practices,
log_triggers,
web_user_responses,
exceptions,
trusted_sources,
source_identifiers
);
return appsec_policy;
}
// LCOV_EXCL_START Reason: no test exist
void
K8sPolicyUtils::createSnortFile(vector<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>
K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spec,
const string &ingress_mode) const
{
NewParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule();
vector<NewParsedRule> specific_rules = appsec_policy_spec.getSpec().getSpecificRules();
string appsec_class_name = appsec_policy_spec.getSpec().getAppSecClassName();
if (getAppSecClassNameFromCluster() != "" &&
appsec_class_name != getAppSecClassNameFromCluster()) {
return genError("Unmached appsec class name!");
}
if (default_rule.getMode().empty() && !ingress_mode.empty()) {
default_rule.setMode(ingress_mode);
}
map<AnnotationTypes, unordered_set<string>> policy_elements_names = extractElementsNamesV1beta2(
specific_rules,
default_rule
);
vector<NewAppSecPracticeSpec> threat_prevention_practices =
extractV1Beta2ElementsFromCluster<NewAppSecPracticeSpec>(
"threatpreventionpractices",
policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE]
);
createSnortFile(threat_prevention_practices);
vector<AccessControlPracticeSpec> access_control_practices =
extractV1Beta2ElementsFromCluster<AccessControlPracticeSpec>(
"accesscontrolpractice",
policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE]
);
vector<NewAppsecLogTrigger> log_triggers = extractV1Beta2ElementsFromCluster<NewAppsecLogTrigger>(
"logtriggers",
policy_elements_names[AnnotationTypes::TRIGGER]
);
vector<NewAppSecCustomResponse> web_user_responses = extractV1Beta2ElementsFromCluster<NewAppSecCustomResponse>(
"customresponses",
policy_elements_names[AnnotationTypes::WEB_USER_RES]
);
vector<NewAppsecException> exceptions = extractV1Beta2ElementsFromCluster<NewAppsecException>(
"exceptions",
policy_elements_names[AnnotationTypes::EXCEPTION]
);
vector<NewSourcesIdentifiers> source_identifiers = extractV1Beta2ElementsFromCluster<NewSourcesIdentifiers>(
"sourcesidentifiers",
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS]
);
vector<NewTrustedSourcesSpec> trusted_sources = extractV1Beta2ElementsFromCluster<NewTrustedSourcesSpec>(
"trustedsources",
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES]
);
V1beta2AppsecLinuxPolicy appsec_policy = V1beta2AppsecLinuxPolicy(
appsec_policy_spec.getSpec(),
threat_prevention_practices,
access_control_practices,
log_triggers,
web_user_responses,
exceptions,
trusted_sources,
source_identifiers
);
return appsec_policy;
}
// LCOV_EXCL_STOP
bool
doesVersionExist(const map<string, string> &annotations, const string &version)
{
for (auto annotation : annotations) {
if(annotation.second.find(version) != std::string::npos) {
return true;
}
}
return false;
}
std::tuple<Maybe<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const
{
auto maybe_appsec_policy_spec = getObjectFromCluster<AppsecSpecParser<AppsecPolicySpec>>(
"/apis/openappsec.io/v1beta1/policies/" + policy_name
);
if (!maybe_appsec_policy_spec.ok() ||
!doesVersionExist(maybe_appsec_policy_spec.unpack().getMetaData().getAnnotations(), "v1beta1")
) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve Appsec policy with crds version: v1beta1, Trying version: v1beta2";
auto maybe_v1beta2_appsec_policy_spec = getObjectFromCluster<AppsecSpecParser<NewAppsecPolicySpec>>(
"/apis/openappsec.io/v1beta2/policies/" + policy_name
);
if(!maybe_v1beta2_appsec_policy_spec.ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve AppSec policy. Error: "
<< maybe_v1beta2_appsec_policy_spec.getErr();
return std::make_tuple(
genError("Failed to retrieve AppSec v1beta1 policy. Error: " + maybe_appsec_policy_spec.getErr()),
genError(
"Failed to retrieve AppSec v1beta2 policy. Error: " + maybe_v1beta2_appsec_policy_spec.getErr()));
}
return std::make_tuple(
genError("There is no v1beta1 policy"),
createAppsecPolicyK8sFromV1beta2Crds(maybe_v1beta2_appsec_policy_spec.unpack(), ingress_mode));
}
return std::make_tuple(
createAppsecPolicyK8sFromV1beta1Crds(maybe_appsec_policy_spec.unpack(), ingress_mode),
genError("There is no v1beta2 policy"));
}
template<class T, class K>
void
K8sPolicyUtils::createPolicy(
T &appsec_policy,
map<std::string, T> &policies,
map<AnnotationKeys, string> &annotations_values,
const SingleIngressData &item) const
{
for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
string url = rule.getHost();
for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) {
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Host data to the specific asset set:"
<< "URL: '"
<< url
<< "' uri: '"
<< uri.getPath()
<< "'";
K ingress_rule = K(url + uri.getPath());
appsec_policy.addSpecificRule(ingress_rule);
}
}
}
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
std::tuple<map<string, AppsecLinuxPolicy>, map<string, V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPoliciesFromIngresses()
{
dbgFlow(D_LOCAL_POLICY) << "Getting all policy object from Ingresses";
map<string, AppsecLinuxPolicy> v1bet1_policies;
map<string, V1beta2AppsecLinuxPolicy> v1bet2_policies;
auto maybe_ingress = getObjectFromCluster<IngressData>("/apis/networking.k8s.io/v1/ingresses");
if (!maybe_ingress.ok()) {
// TBD: Error handling : INXT-31444
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve K8S Ingress configurations. Error: "
<< maybe_ingress.getErr();
return make_tuple(v1bet1_policies, v1bet2_policies);
}
IngressData ingress = maybe_ingress.unpack();
for (const SingleIngressData &item : ingress.getItems()) {
map<AnnotationKeys, string> annotations_values = parseIngressAnnotations(
item.getMetadata().getAnnotations()
);
if (annotations_values[AnnotationKeys::PolicyKey].empty()) {
dbgInfo(D_LOCAL_POLICY) << "No policy was found in this ingress";
continue;
}
auto maybe_appsec_policy = createAppsecPolicyK8s(
annotations_values[AnnotationKeys::PolicyKey],
annotations_values[AnnotationKeys::ModeKey]
);
if (!std::get<0>(maybe_appsec_policy).ok() && !std::get<1>(maybe_appsec_policy).ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to create appsec policy. Error: "
<< std::get<1>(maybe_appsec_policy).getErr();
continue;
}
if (!std::get<0>(maybe_appsec_policy).ok()) {
auto appsec_policy=std::get<1>(maybe_appsec_policy).unpack();
createPolicy<V1beta2AppsecLinuxPolicy, NewParsedRule>(
appsec_policy,
v1bet2_policies,
annotations_values,
item);
} else {
auto appsec_policy=std::get<0>(maybe_appsec_policy).unpack();
createPolicy<AppsecLinuxPolicy, ParsedRule>(
appsec_policy,
v1bet1_policies,
annotations_values,
item);
}
}
return make_tuple(v1bet1_policies, v1bet2_policies);
}

View File

@@ -43,7 +43,7 @@
#include "include/rules_config_section.h"
#include "include/trusted_sources_section.h"
#include "include/policy_maker_utils.h"
#include "include/k8s_policy_utils.h"
#include "k8s_policy_utils.h"
#include "i_env_details.h"
using namespace std;
@@ -64,31 +64,10 @@ public:
void
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
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";
@@ -104,36 +83,34 @@ public:
{
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment";
map<string, AppsecLinuxPolicy> appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses();
return policy_maker_utils.proccesMultipleAppsecPolicies(
appsec_policies,
dbgInfo(D_LOCAL_POLICY) << "Initializing K8S policy generator";
K8sPolicyUtils k8s_policy_utils;
k8s_policy_utils.init();
auto appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses();
if (!std::get<0>(appsec_policies).empty()) {
return policy_maker_utils.proccesMultipleAppsecPolicies<AppsecLinuxPolicy, ParsedRule>(
std::get<0>(appsec_policies),
policy_version,
default_local_appsec_policy_path
);
}
return policy_maker_utils.proccesMultipleAppsecPolicies<V1beta2AppsecLinuxPolicy, NewParsedRule>(
std::get<1>(appsec_policies),
policy_version,
default_local_appsec_policy_path
);
}
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:
bool
isK8sEnv()
{
return env_type == EnvType::K8S;
}
I_EnvDetails* env_details = nullptr;
EnvType env_type;
PolicyMakerUtils policy_maker_utils;
K8sPolicyUtils k8s_policy_utils;
string local_policy_path;
};

View File

@@ -0,0 +1,72 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_appsec_linux_policy.h"
// LCOV_EXCL_START Reason: no test exist
using namespace std;
const NewAppsecPolicySpec &
V1beta2AppsecLinuxPolicy::getAppsecPolicySpec() const
{
return policies;
}
const vector<NewAppSecPracticeSpec> &
V1beta2AppsecLinuxPolicy::getAppSecPracticeSpecs() const
{
return threat_prevection_practices;
}
const vector<AccessControlPracticeSpec> &
V1beta2AppsecLinuxPolicy::getAccessControlPracticeSpecs() const
{
return access_control_practices;
}
const vector<NewAppsecLogTrigger> &
V1beta2AppsecLinuxPolicy::getAppsecTriggerSpecs() const
{
return log_triggers;
}
const vector<NewAppSecCustomResponse> &
V1beta2AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
{
return custom_responses;
}
const vector<NewAppsecException> &
V1beta2AppsecLinuxPolicy::getAppsecExceptions() const
{
return exceptions;
}
const vector<NewTrustedSourcesSpec> &
V1beta2AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const
{
return trusted_sources;
}
const vector<NewSourcesIdentifiers> &
V1beta2AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
{
return sources_identifiers;
}
void
V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule)
{
policies.addSpecificRule(_rule);
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,154 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_appsec_policy_crd_parser.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"};
void
NewParsedRule::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec NewParsedRule";
parseAppsecJSONKey<vector<string>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<vector<string>>("triggers", log_triggers, archive_in);
parseAppsecJSONKey<vector<string>>("threatPreventionPractices", threat_prevention_practices, archive_in);
parseAppsecJSONKey<vector<string>>("accessControlPractices", access_control_practices, archive_in);
parseAppsecJSONKey<string>("mode", mode, archive_in);
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec New Parsed Rule mode invalid: " << mode;
}
parseAppsecJSONKey<string>("customResponse", custom_response, archive_in);
parseAppsecJSONKey<string>("sourceIdentifiers", source_identifiers, archive_in);
parseAppsecJSONKey<string>("trustedSources", trusted_sources, archive_in);
try {
archive_in(cereal::make_nvp("host", host));
} catch (const cereal::Exception &e)
{
// The default NewParsedRule does not hold a host, so by default it will be *
host = "*";
}
}
const vector<string> &
NewParsedRule::getLogTriggers() const
{
return log_triggers;
}
const vector<string> &
NewParsedRule::getExceptions() const
{
return exceptions;
}
const vector<string> &
NewParsedRule::getPractices() const
{
return threat_prevention_practices;
}
const vector<string> &
NewParsedRule::getAccessControlPractices() const
{
return access_control_practices;
}
const string &
NewParsedRule::getSourceIdentifiers() const
{
return source_identifiers;
}
const string &
NewParsedRule::getCustomResponse() const
{
return custom_response;
}
const string &
NewParsedRule::getTrustedSources() const
{
return trusted_sources;
}
const string &
NewParsedRule::getHost() const
{
return host;
}
const string &
NewParsedRule::getMode() const
{
return mode;
}
void
NewParsedRule::setHost(const string &_host)
{
host = _host;
}
void
NewParsedRule::setMode(const string &_mode)
{
mode = _mode;
}
void
NewAppsecPolicySpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewParsedRule>("default", default_rule, archive_in);
parseAppsecJSONKey<vector<NewParsedRule>>("specificRules", specific_rules, archive_in);
}
const NewParsedRule &
NewAppsecPolicySpec::getDefaultRule() const
{
return default_rule;
}
const vector<NewParsedRule> &
NewAppsecPolicySpec::getSpecificRules() const
{
return specific_rules;
}
const string &
NewAppsecPolicySpec::getAppSecClassName() const
{
return appsec_class_name;
}
bool
NewAppsecPolicySpec::isAssetHostExist(const std::string &full_url) const
{
for (const NewParsedRule &rule : specific_rules) {
if (rule.getHost() == full_url) return true;
}
return false;
}
void
NewAppsecPolicySpec::addSpecificRule(const NewParsedRule &_rule)
{
specific_rules.push_back(_rule);
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,99 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_custom_response.h"
#define MIN_RESPONSE_CODE 100
#define MAX_RESPOMSE_CODE 599
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_modes = {"block-page", "response-code-only", "redirect"};
void
NewAppSecCustomResponse::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec web user response spec";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<int>("httpResponseCode", http_response_code, archive_in, 403);
if (http_response_code < MIN_RESPONSE_CODE || http_response_code > MAX_RESPOMSE_CODE) {
dbgWarning(D_LOCAL_POLICY) << "AppSec web user response code invalid: " << http_response_code;
}
parseAppsecJSONKey<string>("mode", mode, archive_in, "block-page");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec web user response mode invalid: " << mode;
}
parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("redirectUrl", redirect_url, archive_in);
parseAppsecJSONKey<bool>("redirectAddXEventId", redirect_add_x_event_id, archive_in);
if (mode == "block-page") {
parseAppsecJSONKey<string>(
"messageBody",
message_body,
archive_in,
"Openappsec's <b>Application Security</b> has detected an attack and blocked it."
);
parseAppsecJSONKey<string>(
"messageTitle",
message_title,
archive_in,
"Attack blocked by web application protection"
);
}
}
void
NewAppSecCustomResponse::setName(const string &_name)
{
name = _name;
}
int
NewAppSecCustomResponse::getHttpResponseCode() const
{
return http_response_code;
}
const string &
NewAppSecCustomResponse::getMessageBody() const
{
return message_body;
}
const string &
NewAppSecCustomResponse::getMessageTitle() const
{
return message_title;
}
const string &
NewAppSecCustomResponse::getAppSecClassName() const
{
return appsec_class_name;
}
const string &
NewAppSecCustomResponse::getMode() const
{
return mode;
}
const string &
NewAppSecCustomResponse::getName() const
{
return name;
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,187 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_exceptions.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_actions = {"skip", "accept", "drop", "suppressLog"};
void
NewAppsecExceptionCondition::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception condition";
parseAppsecJSONKey<string>("key", key, archive_in);
parseAppsecJSONKey<string>("value", value, archive_in);
}
const string &
NewAppsecExceptionCondition::getKey() const
{
return key;
}
const string &
NewAppsecExceptionCondition::getvalue() const
{
return value;
}
void
NewAppsecException::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception";
parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
if (valid_actions.count(action) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action;
}
parseAppsecJSONKey<vector<NewAppsecExceptionCondition>>("condition", conditions, archive_in);
}
void
NewAppsecException::setName(const string &_name)
{
name = _name;
}
const string &
NewAppsecException::getName() const
{
return name;
}
const string &
NewAppsecException::getAction() const
{
return action;
}
const string &
NewAppsecException::getAppSecClassName() const
{
return appsec_class_name;
}
const vector<string>
NewAppsecException::getCountryCode() const
{
vector<string> country_codes;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "countryCode") {
country_codes.push_back(condition.getvalue());
}
}
return country_codes;
}
const vector<string>
NewAppsecException::getCountryName() const
{
vector<string> country_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "countryName") {
country_names.push_back(condition.getvalue());
}
}
return country_names;
}
const vector<string>
NewAppsecException::getHostName() const
{
vector<string> host_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "hostName") {
host_names.push_back(condition.getvalue());
}
}
return host_names;
}
const vector<string>
NewAppsecException::getParamName() const
{
vector<string> param_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "paramName") {
param_names.push_back(condition.getvalue());
}
}
return param_names;
}
const vector<string>
NewAppsecException::getParamValue() const
{
vector<string> param_values;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "paramValue") {
param_values.push_back(condition.getvalue());
}
}
return param_values;
}
const vector<string>
NewAppsecException::getProtectionName() const
{
vector<string> protection_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "protectionName") {
protection_names.push_back(condition.getvalue());
}
}
return protection_names;
}
const vector<string>
NewAppsecException::getSourceIdentifier() const
{
vector<string> source_identifiers;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "sourceIdentifier") {
source_identifiers.push_back(condition.getvalue());
}
}
return source_identifiers;
}
const vector<string>
NewAppsecException::getSourceIp() const
{
vector<string> source_ips;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "sourceIp") {
source_ips.push_back(condition.getvalue());
}
}
return source_ips;
}
const vector<string>
NewAppsecException::getUrl() const
{
vector<string> urls;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "url") {
urls.push_back(condition.getvalue());
}
}
return urls;
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,321 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_log_trigger.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_severities = {"high", "critical"};
static const set<string> valid_protocols = {"tcp", "udp"};
static const set<string> valid_formats = {"json", "json-formatted"};
void
NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging";
parseAppsecJSONKey<bool>("allowEvents", allow_events, archive_in, false);
parseAppsecJSONKey<bool>("dropEvents", drop_events, archive_in, false);
}
void
NewAppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging";
parseAppsecJSONKey<bool>("enabled", enabled, archive_in, true);
parseAppsecJSONKey<bool>("responseBody", response_body, archive_in, false);
//the old code didn't parse the responsecode so ask Noam what is the currenct default value for it
parseAppsecJSONKey<bool>("responseCode", response_code, archive_in, false);
parseAppsecJSONKey<string>("minSeverity", minimum_severity, archive_in, "high");
if (valid_severities.count(minimum_severity) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec AppSec Trigger - Additional Suspicious Events Logging minimum severity invalid: "
<< minimum_severity;
}
}
bool
NewAppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const
{
return enabled;
}
bool
NewAppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const
{
return response_body;
}
const string &
NewAppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const
{
return minimum_severity;
}
void
NewAppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Logging";
parseAppsecJSONKey<bool>("detectEvents", detect_events, archive_in, false);
parseAppsecJSONKey<bool>("preventEvents", prevent_events, archive_in, true);
parseAppsecJSONKey<bool>("allWebRequests", all_web_requests, archive_in, false);
}
bool
NewAppsecTriggerLogging::isAllWebRequests() const
{
return all_web_requests;
}
bool
NewAppsecTriggerLogging::isDetectEvents() const
{
return detect_events;
}
bool
NewAppsecTriggerLogging::isPreventEvents() const
{
return prevent_events;
}
void
NewAppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Extended Logging";
parseAppsecJSONKey<bool>("httpHeaders", http_headers, archive_in, false);
parseAppsecJSONKey<bool>("requestBody", request_body, archive_in, false);
parseAppsecJSONKey<bool>("urlPath", url_path, archive_in, false);
parseAppsecJSONKey<bool>("urlQuery", url_query, archive_in, false);
}
bool
NewAppsecTriggerExtendedLogging::isHttpHeaders() const
{
return http_headers;
}
bool
NewAppsecTriggerExtendedLogging::isRequestBody() const
{
return request_body;
}
bool
NewAppsecTriggerExtendedLogging::isUrlPath() const
{
return url_path;
}
bool
NewAppsecTriggerExtendedLogging::isUrlQuery() const
{
return url_query;
}
void
NewLoggingService::load(cereal::JSONInputArchive &archive_in)
{
parseAppsecJSONKey<string>("address", address, archive_in);
parseAppsecJSONKey<string>("proto", proto, archive_in);
if (valid_protocols.count(proto) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto;
}
parseAppsecJSONKey<int>("port", port, archive_in, 514);
}
const string &
NewLoggingService::getAddress() const
{
return address;
}
int
NewLoggingService::getPort() const
{
return port;
}
void
NewStdoutLogging::load(cereal::JSONInputArchive &archive_in)
{
parseAppsecJSONKey<string>("format", format, archive_in, "json");
if (valid_formats.count(format) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Stdout Logging - format invalid: " << format;
}
}
const string &
NewStdoutLogging::getFormat() const
{
return format;
}
void
NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination";
// TBD: support "file"
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
auto mode = Singleton::Consume<I_AgentDetails>::by<NewAppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<NewAppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
NewStdoutLogging stdout_log;
parseAppsecJSONKey<NewStdoutLogging>("stdout", stdout_log, archive_in);
agent_local = !(stdout_log.getFormat().empty());
beautify_logs = stdout_log.getFormat() == "json-formatted";
parseAppsecJSONKey<NewLoggingService>("syslogService", syslog_service, archive_in);
parseAppsecJSONKey<NewLoggingService>("cefService", cef_service, archive_in);
}
int
NewAppsecTriggerLogDestination::getCefServerUdpPort() const
{
return getCefServiceData().getPort();
}
int
NewAppsecTriggerLogDestination::getSyslogServerUdpPort() const
{
return getSyslogServiceData().getPort();
}
bool
NewAppsecTriggerLogDestination::isAgentLocal() const
{
return agent_local;
}
bool
NewAppsecTriggerLogDestination::shouldBeautifyLogs() const
{
return beautify_logs;
}
bool
NewAppsecTriggerLogDestination::getCloud() const
{
return cloud;
}
bool
NewAppsecTriggerLogDestination::isK8SNeeded() const
{
return k8s_service;
}
bool
NewAppsecTriggerLogDestination::isCefNeeded() const
{
return !getCefServiceData().getAddress().empty();
}
bool
NewAppsecTriggerLogDestination::isSyslogNeeded() const
{
return !getSyslogServiceData().getAddress().empty();
}
const
string & NewAppsecTriggerLogDestination::getSyslogServerIpv4Address() const
{
return getSyslogServiceData().getAddress();
}
const string &
NewAppsecTriggerLogDestination::getCefServerIpv4Address() const
{
return getCefServiceData().getAddress();
}
const NewLoggingService &
NewAppsecTriggerLogDestination::getSyslogServiceData() const
{
return syslog_service;
}
const NewLoggingService &
NewAppsecTriggerLogDestination::getCefServiceData() const
{
return cef_service;
}
void
NewAppsecLogTrigger::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec log trigger";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewAppsecTriggerAccessControlLogging>(
"accessControlLogging",
access_control_logging,
archive_in
);
parseAppsecJSONKey<NewAppsecTriggerAdditionalSuspiciousEventsLogging>(
"additionalSuspiciousEventsLogging",
additional_suspicious_events_logging,
archive_in
);
parseAppsecJSONKey<NewAppsecTriggerLogging>("appsecLogging", appsec_logging, archive_in);
parseAppsecJSONKey<NewAppsecTriggerExtendedLogging>("extendedLogging", extended_logging, archive_in);
parseAppsecJSONKey<NewAppsecTriggerLogDestination>("logDestination", log_destination, archive_in);
parseAppsecJSONKey<string>("name", name, archive_in);
}
void
NewAppsecLogTrigger::setName(const string &_name)
{
name = _name;
}
const string &
NewAppsecLogTrigger::getName() const
{
return name;
}
const string &
NewAppsecLogTrigger::getAppSecClassName() const
{
return appsec_class_name;
}
const NewAppsecTriggerAdditionalSuspiciousEventsLogging &
NewAppsecLogTrigger::getAppsecTriggerAdditionalSuspiciousEventsLogging() const
{
return additional_suspicious_events_logging;
}
const NewAppsecTriggerLogging &
NewAppsecLogTrigger::getAppsecTriggerLogging() const
{
return appsec_logging;
}
const NewAppsecTriggerExtendedLogging &
NewAppsecLogTrigger::getAppsecTriggerExtendedLogging() const
{
return extended_logging;
}
const NewAppsecTriggerLogDestination &
NewAppsecLogTrigger::getAppsecTriggerLogDestination() const
{
return log_destination;
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,986 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_practice.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> performance_impacts = {"low", "medium", "high"};
static const set<string> severity_levels = {"low", "medium", "high", "critical"};
static const set<string> size_unit = {"bytes", "KB", "MB", "GB"};
static const set<string> confidences_actions = {"prevent", "detect", "inactive"};
static const set<string> valid_modes = {"prevent", "detect", "inactive", "prevent-learn", "detect-learn"};
static const set<string> valid_confidences = {"medium", "high", "critical"};
static const std::unordered_map<std::string, std::string> key_to_performance_impact_val = {
{ "low", "Low or lower"},
{ "medium", "Medium or lower"},
{ "high", "High or lower"}
};
static const std::unordered_map<std::string, std::string> key_to_severity_level_val = {
{ "low", "Low or above"},
{ "medium", "Medium or above"},
{ "high", "High or above"},
{ "critical", "Critical"}
};
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, int> unit_to_int = {
{ "bytes", 1},
{ "KB", 1024},
{ "MB", 1048576},
{ "GB", 1073741824}
};
void
NewAppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots URI";
parseAppsecJSONKey<string>("uri", uri, archive_in);
}
const string &
NewAppSecWebBotsURI::getURI() const
{
return uri;
}
std::vector<std::string>
NewAppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
return injected;
}
std::vector<std::string>
NewAppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> validated;
for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
return validated;
}
void
NewAppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots";
parseAppsecJSONKey<vector<NewAppSecWebBotsURI>>("injectedUris", injected_uris, archive_in);
parseAppsecJSONKey<vector<NewAppSecWebBotsURI>>("validatedUris", validated_uris, archive_in);
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "Inactive");
if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << override_mode;
}
}
void
NewAppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> injected;
vector<string> validated;
for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
out_ar(
cereal::make_nvp("injected", injected),
cereal::make_nvp("validated", validated)
);
}
void
NewAppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Attack Protections";
parseAppsecJSONKey<string>("csrfEnabled", csrf_protection, archive_in, "inactive");
parseAppsecJSONKey<string>("errorDisclosureEnabled", error_disclosure, archive_in, "inactive");
parseAppsecJSONKey<string>("openRedirectEnabled", open_redirect, archive_in, "inactive");
parseAppsecJSONKey<bool>("nonValidHttpMethods", non_valid_http_methods, archive_in, false);
}
const string
NewAppSecWebAttackProtections::getCsrfProtectionMode() const
{
if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) {
dbgError(D_LOCAL_POLICY)
<< "Failed to find a value for "
<< csrf_protection
<< ". Setting CSRF protection to Inactive";
return "Inactive";
}
return key_to_practices_val.at(csrf_protection);
}
const string &
NewAppSecWebAttackProtections::getErrorDisclosureMode() const
{
return error_disclosure;
}
bool
NewAppSecWebAttackProtections::getNonValidHttpMethods() const
{
return non_valid_http_methods;
}
const string
NewAppSecWebAttackProtections::getOpenRedirectMode() const
{
if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) {
dbgError(D_LOCAL_POLICY)
<< "Failed to find a value for "
<< open_redirect
<< ". Setting Open Redirect mode to Inactive";
return "Inactive";
}
return key_to_practices_val.at(open_redirect);
}
void
NewAppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice web attacks spec";
parseAppsecJSONKey<NewAppSecWebAttackProtections>("protections", protections, archive_in);
parseAppsecJSONKey<string>("overrideMode", mode, archive_in, "Unset");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec practice override mode invalid: " << mode;
}
if (getMode() == "Prevent") {
parseAppsecJSONKey<string>("minimumConfidence", minimum_confidence, archive_in, "critical");
if (valid_confidences.count(minimum_confidence) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec practice override minimum confidence invalid: "
<< minimum_confidence;
}
} else {
minimum_confidence = "Transparent";
}
parseAppsecJSONKey<int>("maxBodySizeKb", max_body_size_kb, archive_in, 1000000);
parseAppsecJSONKey<int>("maxHeaderSizeBytes", max_header_size_bytes, archive_in, 102400);
parseAppsecJSONKey<int>("maxObjectDepth", max_object_depth, archive_in, 40);
parseAppsecJSONKey<int>("maxUrlSizeBytes", max_url_size_bytes, archive_in, 32768);
}
int
NewAppSecPracticeWebAttacks::getMaxBodySizeKb() const
{
return max_body_size_kb;
}
int
NewAppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const
{
return max_header_size_bytes;
}
int
NewAppSecPracticeWebAttacks::getMaxObjectDepth() const
{
return max_object_depth;
}
int
NewAppSecPracticeWebAttacks::getMaxUrlSizeBytes() const
{
return max_url_size_bytes;
}
const string &
NewAppSecPracticeWebAttacks::getMinimumConfidence() const
{
return minimum_confidence;
}
const string &
NewAppSecPracticeWebAttacks::getMode(const string &default_mode) const
{
if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) {
dbgError(D_LOCAL_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode;
return default_mode;
}
return key_to_practices_val.at(mode);
}
SnortProtectionsSection::SnortProtectionsSection(
const std::string &_context,
const std::string &_asset_name,
const std::string &_asset_id,
const std::string &_practice_name,
const std::string &_practice_id,
const std::string &_source_identifier,
const std::string &_mode,
const std::vector<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
NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in);
if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode;
}
}
void
NewSnortSignaturesAndOpenSchemaAPI::addFile(const string &file_name)
{
files.push_back(file_name);
}
const string &
NewSnortSignaturesAndOpenSchemaAPI::getOverrideMode() const
{
return override_mode;
}
const vector<string> &
NewSnortSignaturesAndOpenSchemaAPI::getFiles() const
{
return files;
}
const vector<string> &
NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const
{
return config_map;
}
void
IpsProtectionsRulesSection::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> protections;
out_ar(
cereal::make_nvp("action", key_to_mode_val.at(action)),
cereal::make_nvp("confidenceLevel", confidence_level),
cereal::make_nvp("clientProtections", true),
cereal::make_nvp("serverProtections", true),
cereal::make_nvp("protectionTags", protections),
cereal::make_nvp("protectionIds", protections),
cereal::make_nvp("performanceImpact", key_to_performance_impact_val.at(performance_impact)),
cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)),
cereal::make_nvp("protectionsFromYear", protections_from_year)
);
}
IpsProtectionsSection::IpsProtectionsSection(
const string &_context,
const string &asset_name,
const string &_asset_id,
const string &_practice_name,
const string &_practice_id,
const string &_source_identifier,
const string &_mode,
const vector<IpsProtectionsRulesSection> &_rules)
:
context(_context),
name(asset_name),
asset_id(_asset_id),
practice_name(_practice_name),
practice_id(_practice_id),
source_identifier(_source_identifier),
mode(_mode),
rules(_rules)
{
}
std::string &
IpsProtectionsSection::getMode()
{
return mode;
}
void
IpsProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("ruleName", name),
cereal::make_nvp("assetName", name),
cereal::make_nvp("assetId", asset_id),
cereal::make_nvp("practiceName", practice_name),
cereal::make_nvp("practiceId", practice_id),
cereal::make_nvp("sourceIdentifier", source_identifier),
cereal::make_nvp("defaultAction", key_to_mode_val.at(mode)),
cereal::make_nvp("rules", rules)
);
}
void
IPSSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("IpsProtections", ips)
);
}
void
IntrusionPreventionWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("IPS", ips)
);
}
void
NewIntrusionPrevention::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Intrusion Prevention practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Intrusion Prevention override mode invalid: " << override_mode;
}
parseAppsecJSONKey<string>("maxPerformanceImpact", max_performance_impact, archive_in, "low");
if (performance_impacts.count(max_performance_impact) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec Intrusion Prevention max performance impact invalid: "
<< max_performance_impact;
}
parseAppsecJSONKey<string>("minSeverityLevel", min_severity_level, archive_in, "low");
if (severity_levels.count(min_severity_level) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec Intrusion Prevention min severity level invalid: "
<< min_severity_level;
}
parseAppsecJSONKey<string>("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(high_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec Intrusion Prevention high confidence event invalid: "
<< high_confidence_event_action;
}
parseAppsecJSONKey<string>("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(medium_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec Intrusion Prevention medium confidence event invalid: "
<< medium_confidence_event_action;
}
parseAppsecJSONKey<string>("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(low_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec Intrusion Prevention low confidence event action invalid: "
<< low_confidence_event_action;
}
parseAppsecJSONKey<int>("minCveYear", min_cve_Year, archive_in);
}
vector<IpsProtectionsRulesSection>
NewIntrusionPrevention::createIpsRules() const
{
vector<IpsProtectionsRulesSection> ips_rules;
IpsProtectionsRulesSection high_rule(
min_cve_Year,
high_confidence_event_action,
string("High"),
max_performance_impact,
string(""),
min_severity_level
);
ips_rules.push_back(high_rule);
IpsProtectionsRulesSection med_rule(
min_cve_Year,
medium_confidence_event_action,
string("Medium"),
max_performance_impact,
string(""),
min_severity_level
);
ips_rules.push_back(med_rule);
IpsProtectionsRulesSection low_rule(
min_cve_Year,
low_confidence_event_action,
string("Low"),
max_performance_impact,
string(""),
min_severity_level
);
ips_rules.push_back(low_rule);
return ips_rules;
}
const std::string &
NewIntrusionPrevention::getMode() const
{
return override_mode;
}
FileSecurityProtectionsSection::FileSecurityProtectionsSection(
int _file_size_limit,
int _archive_file_size_limit,
bool _allow_files_without_name,
bool _required_file_size_limit,
bool _required_archive_extraction,
const std::string &_context,
const std::string &_name,
const std::string &_asset_id,
const std::string &_practice_name,
const std::string &_practice_id,
const std::string &_action,
const std::string &_files_without_name_action,
const std::string &_high_confidence_action,
const std::string &_medium_confidence_action,
const std::string &_low_confidence_action,
const std::string &_severity_level,
const std::string &_file_size_limit_action,
const std::string &_multi_level_archive_action,
const std::string &_unopened_archive_action)
:
file_size_limit(_file_size_limit),
archive_file_size_limit(_archive_file_size_limit),
allow_files_without_name(_allow_files_without_name),
required_file_size_limit(_required_file_size_limit),
required_archive_extraction(_required_archive_extraction),
context(_context),
name(_name),
asset_id(_asset_id),
practice_name(_practice_name),
practice_id(_practice_id),
action(_action),
files_without_name_action(_files_without_name_action),
high_confidence_action(_high_confidence_action),
medium_confidence_action(_medium_confidence_action),
low_confidence_action(_low_confidence_action),
severity_level(_severity_level),
file_size_limit_action(_file_size_limit_action),
multi_level_archive_action(_multi_level_archive_action),
unopened_archive_action(_unopened_archive_action)
{}
void
FileSecurityProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("ruleName", name),
cereal::make_nvp("assetName", name),
cereal::make_nvp("assetId", asset_id),
cereal::make_nvp("practiceName", practice_name),
cereal::make_nvp("practiceId", practice_id),
cereal::make_nvp("action", key_to_mode_val.at(action)),
cereal::make_nvp("filesWithoutNameAction", key_to_mode_val.at(files_without_name_action)),
cereal::make_nvp("allowFilesWithoutName", allow_files_without_name),
cereal::make_nvp("highConfidence", key_to_mode_val.at(high_confidence_action)),
cereal::make_nvp("mediumConfidence", key_to_mode_val.at(medium_confidence_action)),
cereal::make_nvp("lowConfidence", key_to_mode_val.at(low_confidence_action)),
cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)),
cereal::make_nvp("fileSizeLimitAction", key_to_mode_val.at(file_size_limit_action)),
cereal::make_nvp("fileSizeLimit", file_size_limit),
cereal::make_nvp("requiredFileSizeLimit", required_file_size_limit),
cereal::make_nvp("requiredArchiveExtraction", required_archive_extraction),
cereal::make_nvp("archiveFileSizeLimit", archive_file_size_limit),
cereal::make_nvp("MultiLevelArchiveAction", key_to_mode_val.at(multi_level_archive_action)),
cereal::make_nvp("UnopenedArchiveAction", key_to_mode_val.at(unopened_archive_action))
);
}
void
FileSecuritySection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("FileSecurityProtections", file_security)
);
}
void
FileSecurityWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("FileSecurity", file_security)
);
}
void
NewFileSecurityArchiveInspection::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security Archive Inspection practice";
parseAppsecJSONKey<bool>("extractArchiveFiles", extract_archive_files, archive_in);
parseAppsecJSONKey<int>("scanMaxFileSize", scan_max_file_size, archive_in, 0);
parseAppsecJSONKey<string>("scanMaxFileSizeUnit", scan_max_file_size_unit, archive_in, "bytes");
if (size_unit.count(scan_max_file_size_unit) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security Archive Inspection scan max file size unit invalid: "
<< scan_max_file_size_unit;
}
parseAppsecJSONKey<string>(
"archivedFilesWithinArchivedFiles",
archived_files_within_archived_files,
archive_in,
"inactive");
if (confidences_actions.count(archived_files_within_archived_files) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security Archive Inspection archived files within archived files invalid: "
<< archived_files_within_archived_files;
}
parseAppsecJSONKey<string>(
"archivedFilesWhereContentExtractionFailed",
archived_files_where_content_extraction_failed,
archive_in,
"inactive");
if (confidences_actions.count(archived_files_where_content_extraction_failed) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security Archive Inspection archived files within archived file invalid: "
<< archived_files_where_content_extraction_failed;
}
}
int
NewFileSecurityArchiveInspection::getArchiveFileSizeLimit() const
{
if (unit_to_int.find(scan_max_file_size_unit) == unit_to_int.end()) {
dbgError(D_LOCAL_POLICY)
<< "Failed to find a value for "
<< scan_max_file_size_unit
<< ". Setting scan max file size unit to 0";
return 0;
}
return (scan_max_file_size * unit_to_int.at(scan_max_file_size_unit));
}
bool
NewFileSecurityArchiveInspection::getrequiredArchiveExtraction() const
{
return extract_archive_files;
}
const std::string &
NewFileSecurityArchiveInspection::getMultiLevelArchiveAction() const
{
return archived_files_within_archived_files;
}
const std::string &
NewFileSecurityArchiveInspection::getUnopenedArchiveAction() const
{
return archived_files_where_content_extraction_failed;
}
void
NewFileSecurityLargeFileInspection::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security large File Inspection practice";
parseAppsecJSONKey<int>("fileSizeLimit", file_size_limit, archive_in);
parseAppsecJSONKey<string>("fileSizeLimitUnit", file_size_limit_unit, archive_in, "bytes");
if (size_unit.count(file_size_limit_unit) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security large File Inspection file size limit unit invalid: "
<< file_size_limit_unit;
}
parseAppsecJSONKey<string>(
"filesExceedingSizeLimitAction",
files_exceeding_size_limit_action,
archive_in,
"inactive");
if (confidences_actions.count(files_exceeding_size_limit_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security Archive Inspection archived files within archived files invalid: "
<< files_exceeding_size_limit_action;
}
}
int
NewFileSecurityLargeFileInspection::getFileSizeLimit() const
{
if (unit_to_int.find(file_size_limit_unit) == unit_to_int.end()) {
dbgError(D_LOCAL_POLICY)
<< "Failed to find a value for "
<< file_size_limit_unit
<< ". Setting file size limit unit to 0";
return 0;
}
return (file_size_limit * unit_to_int.at(file_size_limit_unit));
}
const std::string &
NewFileSecurityLargeFileInspection::getFileSizeLimitAction() const
{
return files_exceeding_size_limit_action;
}
void
NewFileSecurity::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security practice";
parseAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec File Security override mode invalid: " << override_mode;
}
parseAppsecJSONKey<string>("minSeverityLevel", min_severity_level, archive_in, "low");
if (severity_levels.count(min_severity_level) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec File Security min severity level invalid: " << min_severity_level;
}
parseAppsecJSONKey<string>("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(high_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security high confidence event invalid: "
<< high_confidence_event_action;
}
parseAppsecJSONKey<string>("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(medium_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security medium confidence event invalid: "
<< medium_confidence_event_action;
}
parseAppsecJSONKey<string>("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive");
if (confidences_actions.count(low_confidence_event_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security low confidence event action invalid: "
<< low_confidence_event_action;
}
parseAppsecJSONKey<string>("unnamedFilesAction", unnamed_files_action, archive_in, "inactive");
if (confidences_actions.count(unnamed_files_action) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec File Security low unnamed files action invalid: "
<< unnamed_files_action;
}
parseAppsecJSONKey<bool>("threatEmulationEnabled", threat_emulation_enabled, archive_in);
parseAppsecJSONKey<NewFileSecurityArchiveInspection>("archiveInspection", archive_inspection, archive_in);
parseAppsecJSONKey<NewFileSecurityLargeFileInspection>("largeFileInspection", large_file_inspection, archive_in);
}
const string &
NewFileSecurity::getOverrideMode() const
{
return override_mode;
}
const NewFileSecurityArchiveInspection &
NewFileSecurity::getArchiveInspection() const
{
return archive_inspection;
}
const NewFileSecurityLargeFileInspection &
NewFileSecurity::getLargeFileInspection() const
{
return large_file_inspection;
}
FileSecurityProtectionsSection
NewFileSecurity::createFileSecurityProtectionsSection(
const string &context,
const string &asset_name,
const string &asset_id,
const string &practice_name,
const string &practice_id) const
{
return FileSecurityProtectionsSection(
getLargeFileInspection().getFileSizeLimit(),
getArchiveInspection().getArchiveFileSizeLimit(),
unnamed_files_action == "prevent" ? true : false,
getLargeFileInspection().getFileSizeLimitAction() == "prevent" ? true : false,
getArchiveInspection().getrequiredArchiveExtraction(),
context,
asset_name,
asset_id,
practice_name,
practice_id,
override_mode,
unnamed_files_action,
high_confidence_event_action,
medium_confidence_event_action,
low_confidence_event_action,
min_severity_level,
getLargeFileInspection().getFileSizeLimitAction(),
getArchiveInspection().getMultiLevelArchiveAction(),
getArchiveInspection().getUnopenedArchiveAction()
);
}
void
NewAppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec";
parseAppsecJSONKey<NewSnortSignaturesAndOpenSchemaAPI>(
"openapi-schema-validation",
openapi_schema_validation,
archive_in
);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewFileSecurity>("fileSecurity", file_security, archive_in);
parseAppsecJSONKey<NewIntrusionPrevention>("intrusionPrevention", intrusion_prevention, archive_in);
parseAppsecJSONKey<NewSnortSignaturesAndOpenSchemaAPI>("snortSignatures", snort_signatures, archive_in);
parseAppsecJSONKey<NewAppSecPracticeWebAttacks>("webAttacks", web_attacks, archive_in);
parseAppsecJSONKey<NewAppSecPracticeAntiBot>("antiBot", anti_bot, archive_in);
parseAppsecJSONKey<string>("name", practice_name, archive_in);
}
void
NewAppSecPracticeSpec::setName(const string &_name)
{
practice_name = _name;
}
const NewSnortSignaturesAndOpenSchemaAPI &
NewAppSecPracticeSpec::getOpenSchemaValidation() const
{
return openapi_schema_validation;
}
NewSnortSignaturesAndOpenSchemaAPI &
NewAppSecPracticeSpec::getSnortSignatures()
{
return snort_signatures;
}
const NewAppSecPracticeWebAttacks &
NewAppSecPracticeSpec::getWebAttacks() const
{
return web_attacks;
}
const NewAppSecPracticeAntiBot &
NewAppSecPracticeSpec::getAntiBot() const
{
return anti_bot;
}
const NewIntrusionPrevention &
NewAppSecPracticeSpec::getIntrusionPrevention() const
{
return intrusion_prevention;
}
const NewFileSecurity &
NewAppSecPracticeSpec::getFileSecurity() const
{
return file_security;
}
const string &
NewAppSecPracticeSpec::getAppSecClassName() const
{
return appsec_class_name;
}
const string &
NewAppSecPracticeSpec::getName() const
{
return practice_name;
}
// LCOV_EXCL_STOP

View File

@@ -0,0 +1,118 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "new_trusted_sources.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_identifiers = {"headerkey", "JWTKey", "cookie", "sourceip", "x-forwarded-for"};
void
NewTrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading trusted sources spec";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
parseAppsecJSONKey<vector<string>>("sourcesIdentifiers", sources_identifiers, archive_in);
parseAppsecJSONKey<string>("name", name, archive_in);
}
void
NewTrustedSourcesSpec::setName(const string &_name)
{
name = _name;
}
int
NewTrustedSourcesSpec::getMinNumOfSources() const
{
return min_num_of_sources;
}
const vector<string> &
NewTrustedSourcesSpec::getSourcesIdentifiers() const
{
return sources_identifiers;
}
const string &
NewTrustedSourcesSpec::getAppSecClassName() const
{
return appsec_class_name;
}
const string &
NewTrustedSourcesSpec::getName() const
{
return name;
}
void
Identifier::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading source identifiers spec";
parseAppsecJSONKey<string>("sourceIdentifier", identifier, archive_in);
if (valid_identifiers.count(identifier) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec identifier invalid: " << identifier;
}
parseAppsecJSONKey<vector<string>>("value", value, archive_in);
}
const string &
Identifier::getIdentifier() const
{
return identifier;
}
const vector<string> &
Identifier::getValues() const
{
return value;
}
void
NewSourcesIdentifiers::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Sources Identifiers";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<vector<Identifier>>("sourcesIdentifiers", sources_identifiers, archive_in);
parseAppsecJSONKey<string>("name", name, archive_in);
}
void
NewSourcesIdentifiers::setName(const string &_name)
{
name = _name;
}
const string &
NewSourcesIdentifiers::getName() const
{
return name;
}
const string &
NewSourcesIdentifiers::getAppSecClassName() const
{
return appsec_class_name;
}
const vector<Identifier> &
NewSourcesIdentifiers::getSourcesIdentifiers() const
{
return sources_identifiers;
}
// LCOV_EXCL_STOP

File diff suppressed because it is too large Load Diff

View File

@@ -98,6 +98,7 @@ PracticeSection::save(cereal::JSONOutputArchive &out_ar) const
);
}
// LCOV_EXCL_START Reason: no test exist
ParametersSection::ParametersSection(
const string &_id,
const string &_name)
@@ -120,6 +121,7 @@ ParametersSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("parameterType", type)
);
}
// LCOV_EXCL_STOP
RulesTriggerSection::RulesTriggerSection(
const string &_name,
@@ -249,6 +251,14 @@ UsersIdentifier::UsersIdentifier(const string &_source_identifier, vector<string
identifier_values(_identifier_values)
{}
// LCOV_EXCL_START Reason: no test exist
const string &
UsersIdentifier::getIdentifier() const
{
return source_identifier;
}
// LCOV_EXCL_STOP
void
UsersIdentifier::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -270,6 +280,14 @@ UsersIdentifiersRulebase::UsersIdentifiersRulebase(
source_identifiers(_source_identifiers)
{}
// LCOV_EXCL_START Reason: no test exist
const string &
UsersIdentifiersRulebase::getIdentifier() const
{
return source_identifiers[0].getIdentifier();
}
// LCOV_EXCL_STOP
void
UsersIdentifiersRulebase::save(cereal::JSONOutputArchive &out_ar) const
{

View File

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

View File

@@ -131,7 +131,7 @@ DetailsResolver::Impl::isReverseProxy()
return is_reverse_proxy.unpack().front() == '1';
}
#endif
return false;
return getenv("DOCKER_RPM_ENABLED") && getenv("DOCKER_RPM_ENABLED") == string("true");
}
bool

View File

@@ -42,6 +42,16 @@ checkSamlPortal(const string &command_output)
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>
checkIDP(shared_ptr<istream> file_stream)
{
@@ -125,44 +135,54 @@ getMgmtObjName(shared_ptr<istream> file_stream)
}
Maybe<string>
getGWIPAddress(shared_ptr<istream> file_stream)
getGWHardware(const string &command_output)
{
return getMgmtObjAttr(file_stream, "ipaddr ");
}
Maybe<string>
getGWHardware(shared_ptr<istream> file_stream)
{
Maybe<string> val = getMgmtObjAttr(file_stream, "appliance_type ");
if(val.ok()) {
if (val == string("software")) return string("Open server");
if (val == string("Maestro Gateway")) return string("Maestro");
if (!command_output.empty()) {
if (command_output == "software") return string("Open server");
if (command_output == "Maestro Gateway") return string("Maestro");
return string(command_output);
}
return val;
return genError("GW Hardware was not found");
}
Maybe<string>
getGWApplicationControlBlade(shared_ptr<istream> file_stream)
getAttr(const string &command_output, const string &error)
{
return getMgmtObjAttr(file_stream, "application_firewall_blade ");
if (!command_output.empty()) {
return string(command_output);
}
return genError(error);
}
Maybe<string>
getGWURLFilteringBlade(shared_ptr<istream> file_stream)
getGWApplicationControlBlade(const string &command_output)
{
return getMgmtObjAttr(file_stream, "advanced_uf_blade ");
return getAttr(command_output, "Application Control Blade was not found");
}
Maybe<string>
getGWIPSecVPNBlade(shared_ptr<istream> file_stream)
getGWURLFilteringBlade(const string &command_output)
{
return getMgmtObjAttr(file_stream, "VPN_1 ");
return getAttr(command_output, "URL Filtering Blade was not found");
}
Maybe<string>
getGWVersion(shared_ptr<istream> file_stream)
getGWIPSecVPNBlade(const string &command_output)
{
return getMgmtObjAttr(file_stream, "svn_version_name ");
return getAttr(command_output, "IPSec VPN Blade was not found");
}
Maybe<string>
getGWIPAddress(const string &command_output)
{
return getAttr(command_output, "IP Address was not found");
}
Maybe<string>
getGWVersion(const string &command_output)
{
return getAttr(command_output, "GW Version was not found");
}
Maybe<string>
@@ -191,56 +211,49 @@ getSmbObjectName(const string &command_output)
}
Maybe<string>
getMgmtParentObjAttr(shared_ptr<istream> file_stream, const string &parent_obj, const string &attr)
getSmbBlade(const string &command_output, const string &error)
{
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;
if (command_output.front() == '1') return string("installed");
if (command_output.front() == '0') return string("not-installed");
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);
return genError(error);
}
Maybe<string>
getSmbGWApplicationControlBlade(const string &command_output)
{
return getSmbBlade(command_output, "Application Control Blade was not found");
}
Maybe<string>
getSmbGWURLFilteringBlade(const string &command_output)
{
return getSmbBlade(command_output, "URL Filterin Blade was not found");
}
Maybe<string>
getSmbGWIPSecVPNBlade(const string &command_output)
{
return getSmbBlade(command_output, "IPSec VPN Blade was not found");
}
#endif // gaia || smb
#if defined(gaia)
Maybe<string>
getMgmtParentObjUid(shared_ptr<istream> file_stream)
getMgmtParentObjUid(const string &command_output)
{
auto maybe_unparsed_uid = getMgmtParentObjAttr(file_stream, "cluster_object", "Uid ");
if (!maybe_unparsed_uid.ok()) {
return maybe_unparsed_uid;
}
const string &unparsed_uid = maybe_unparsed_uid.unpack();
auto maybe_uid = chopHeadAndTail(unparsed_uid, "(\"{", "}\")");
if (!maybe_uid.ok()) {
return maybe_uid;
}
string uid = maybe_uid.unpack();
transform(uid.begin(), uid.end(), uid.begin(), ::tolower);
return uid;
return getAttr(command_output, "Parent object uuid was not found");
}
Maybe<string>
getMgmtParentObjName(shared_ptr<istream> file_stream)
getMgmtParentObjName(const string &command_output)
{
auto maybe_unparsed_name = getMgmtParentObjAttr(file_stream, "cluster_object", "Name ");
if (!maybe_unparsed_name.ok()) {
return maybe_unparsed_name;
}
const string &unparsed_name = maybe_unparsed_name.unpack();
return chopHeadAndTail(unparsed_name, "(", ")");
return getAttr(command_output, "Parent object name was not found");
}
#elif defined(smb)
Maybe<string>
getMgmtParentObjUid(const string &command_output)
getSmbMgmtParentObjUid(const string &command_output)
{
if (!command_output.empty()) {
return command_output;
@@ -249,7 +262,7 @@ getMgmtParentObjUid(const string &command_output)
}
Maybe<string>
getMgmtParentObjName(const string &command_output)
getSmbMgmtParentObjName(const string &command_output)
{
if (!command_output.empty()) {
return command_output;
@@ -277,6 +290,34 @@ getOsRelease(shared_ptr<istream> file_stream)
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)
string &
ltrim(string &s)

View File

@@ -31,34 +31,96 @@
#if defined(gaia) || defined(smb)
SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType)
SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan)
SHELL_CMD_HANDLER("canUpdateSDWanData", "cpsdwan get_data | jq -r .can_update_sdwan_data", checkCanUpdateSDWanData)
SHELL_CMD_HANDLER(
"canUpdateSDWanData",
"CPSDWAN_NOLOGS=1 cpsdwan get_data -f can_update_sdwan_data | jq -r .can_update_sdwan_data",
checkCanUpdateSDWanData
)
SHELL_CMD_HANDLER(
"isSdwanRunning",
"[ -v $(pidof cp-nano-sdwan) ] && echo 'false' || echo 'true'",
checkIfSdwanRunning)
SHELL_CMD_HANDLER(
"IP Address",
"cpsdwan get_data | jq -r .main_ip",
getGWIPAddress
)
SHELL_CMD_HANDLER(
"Version",
"cat /etc/cp-release | grep -oE 'R[0-9]+(\\.[0-9]+)?'",
getGWVersion
)
#endif //gaia || smb
#if defined(gaia)
SHELL_CMD_HANDLER("hasSupportedBlade", "enabled_blades", checkHasSupportedBlade)
SHELL_CMD_HANDLER("hasSamlPortal", "mpclient status saml-vpn", checkSamlPortal)
SHELL_CMD_HANDLER("requiredNanoServices", "mpclient status saml-vpn", getIDAGaia)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectName",
"cat $FWDIR/database/myself_objects.C "
"| awk -F '[:()]' '/:cluster_object/ {found=1; next} found && /:Name/ {print $3; exit}'",
getMgmtParentObjName
)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectUid",
"cat $FWDIR/database/myself_objects.C "
"| awk -F'[{}]' '/:cluster_object/ { found=1; next } found && /:Uid/ { uid=tolower($2); print uid; exit }'",
getMgmtParentObjUid
)
SHELL_CMD_HANDLER(
"Hardware",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1",
getGWHardware
)
SHELL_CMD_HANDLER(
"Application Control",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:application_firewall_blade/ {print $3}' | head -n 1",
getGWApplicationControlBlade
)
SHELL_CMD_HANDLER(
"URL Filtering",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:advanced_uf_blade/ {print $3}' | head -n 1",
getGWURLFilteringBlade
)
SHELL_CMD_HANDLER(
"IPSec VPN",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:VPN_1/ {print $3}' | head -n 1",
getGWIPSecVPNBlade
)
#endif //gaia
#if defined(smb)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectName",
"cpsdwan get_data | jq -r .cluster_name",
getMgmtParentObjName
getSmbMgmtParentObjName
)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectUid",
"cpsdwan get_data | jq -r .cluster_uuid",
getMgmtParentObjUid
getSmbMgmtParentObjUid
)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtObjectName",
"cpprod_util FwIsLocalMgmt",
getSmbObjectName
)
SHELL_CMD_HANDLER(
"Application Control",
"cat $FWDIR/conf/active_blades.txt | grep -o 'APCL [01]' | cut -d ' ' -f2",
getSmbGWApplicationControlBlade
)
SHELL_CMD_HANDLER(
"URL Filtering",
"cat $FWDIR/conf/active_blades.txt | grep -o 'URLF [01]' | cut -d ' ' -f2",
getSmbGWURLFilteringBlade
)
SHELL_CMD_HANDLER(
"IPSec VPN",
"cat $FWDIR/conf/active_blades.txt | grep -o 'IPS [01]' | cut -d ' ' -f2",
getSmbGWIPSecVPNBlade
)
#endif//smb
SHELL_CMD_OUTPUT("kernel_version", "uname -r")
@@ -73,17 +135,6 @@ SHELL_CMD_OUTPUT("helloWorld", "cat /tmp/agentHelloWorld 2>/dev/null")
#if defined(gaia)
FILE_CONTENT_HANDLER("hasIdpConfigured", "/opt/CPSamlPortal/phpincs/spPortal/idpPolicy.xml", checkIDP)
FILE_CONTENT_HANDLER(
"cpProductIntegrationMgmtParentObjectUid",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getMgmtParentObjUid
)
FILE_CONTENT_HANDLER(
"cpProductIntegrationMgmtParentObjectName",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getMgmtParentObjName
)
FILE_CONTENT_HANDLER(
"cpProductIntegrationMgmtObjectName",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C",
@@ -101,39 +152,10 @@ FILE_CONTENT_HANDLER(
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C",
getMgmtObjUid
)
FILE_CONTENT_HANDLER(
"IP Address",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWIPAddress
)
FILE_CONTENT_HANDLER(
"Hardware",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWHardware
)
FILE_CONTENT_HANDLER(
"Application Control",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWApplicationControlBlade
)
FILE_CONTENT_HANDLER(
"URL Filtering",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWURLFilteringBlade
)
FILE_CONTENT_HANDLER(
"IPSec VPN",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWIPSecVPNBlade
)
FILE_CONTENT_HANDLER(
"Version",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C",
getGWVersion
)
#else // !(gaia || smb)
FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease)
#endif // gaia || smb
FILE_CONTENT_HANDLER("AppSecModelVersion", "/etc/cp/conf/waap/waap.data", getWaapModelVersion)
#endif // FILE_CONTENT_HANDLER

View File

@@ -22,6 +22,7 @@
#include "maybe_res.h"
#include "enum_array.h"
#include "i_shell_cmd.h"
#include "i_orchestration_tools.h"
#include "config.h"
using namespace std;
@@ -77,7 +78,8 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
const string &path = file_handler.second.first;
FileContentHandler handler = file_handler.second.second;
shared_ptr<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()) {
dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
continue;

View File

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

View File

@@ -2,4 +2,4 @@ ADD_DEFINITIONS(-Wno-deprecated-declarations -Dalpine)
add_library(orchestration_downloader curl_client.cc downloader.cc http_client.cc https_client.cc)
add_subdirectory(downloader_ut)
#add_subdirectory(downloader_ut)

View File

@@ -278,6 +278,36 @@ HttpsCurl::HttpsCurl(const HttpsCurl &other) :
HttpCurl(other),
ca_path(other.ca_path) {}
bool
HttpsCurl::downloadOpenAppsecPackages()
{
char errorstr[CURL_ERROR_SIZE];
CURL* curl_handle = curl_easy_init();
if (!curl_handle) return false;
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl_handle, CURLOPT_URL, ("https://" + curl_url).c_str());
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeResponseCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &out_file);
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorstr);
CURLcode res = curl_easy_perform(curl_handle);
if (res == CURLE_OK) {
dbgTrace(D_HTTP_REQUEST) << "CURL HTTP request successfully completed.";
} else {
dbgWarning(D_HTTP_REQUEST) << "CURL result " + string(curl_easy_strerror(res));
curl_easy_cleanup(curl_handle);
return false;
}
curl_easy_cleanup(curl_handle);
return true;
}
void
HttpsCurl::setCurlOpts(long timeout, HTTP_VERSION http_version)
{
@@ -299,9 +329,9 @@ HttpsCurl::setCurlOpts(long timeout, HTTP_VERSION http_version)
curl_easy_setopt(curl_handle, CURLOPT_HTTP_VERSION, http_version);
//SSL options
if (getProfileAgentSettingWithDefault<bool>(
false,
"agent.config.message.ignoreSslValidation") == false)
if (
getProfileAgentSettingWithDefault<bool>(false, "agent.config.message.ignoreSslValidation") == false
)
{
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_verify_certificate);

View File

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

View File

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

View File

@@ -179,14 +179,13 @@ private:
Maybe<void>
HTTPClient::getFile(const URLParser &url, ofstream &out_file, bool auth_required)
{
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto load_env_proxy = message->loadProxy();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
auto load_env_proxy = proxy_config->loadProxy();
if (!load_env_proxy.ok()) return load_env_proxy;
string token = "";
if (auth_required) {
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
token = message->getAccessToken();
token = Singleton::Consume<I_AgentDetails>::by<HTTPClient>()->getAccessToken();
}
if (url.isOverSSL()) {
@@ -214,15 +213,15 @@ Maybe<void>
HTTPClient::curlGetFileOverHttp(const URLParser &url, ofstream &out_file, const string &token)
{
try {
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
HttpCurl http_curl_client(
url,
out_file,
token,
message->getProxyDomain(ProxyProtocol::HTTPS),
message->getProxyPort(ProxyProtocol::HTTPS),
message->getProxyCredentials(ProxyProtocol::HTTPS));
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
proxy_config->getProxyCredentials(ProxyProtocol::HTTPS));
http_curl_client.setCurlOpts();
bool connection_ok = http_curl_client.connect();
@@ -247,12 +246,12 @@ Maybe<void>
HTTPClient::getFileHttp(const URLParser &url, ofstream &out_file, const string &token)
{
try {
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
ClientConnection client_connection(
url,
message->getProxyDomain(ProxyProtocol::HTTP),
message->getProxyPort(ProxyProtocol::HTTP),
message->getProxyCredentials(ProxyProtocol::HTTP),
proxy_config->getProxyDomain(ProxyProtocol::HTTP),
proxy_config->getProxyPort(ProxyProtocol::HTTP),
proxy_config->getProxyCredentials(ProxyProtocol::HTTP),
token
);
auto handle_connect_res = client_connection.handleConnect();

View File

@@ -18,9 +18,15 @@
#include "maybe_res.h"
#include "url_parser.h"
#include "i_messaging.h"
#include "i_agent_details.h"
#include "i_proxy_configuration.h"
// LCOV_EXCL_START Reason: Depends on real download server.
class HTTPClient : public Singleton::Consume<I_Messaging>
class HTTPClient
:
public Singleton::Consume<I_Messaging>,
public Singleton::Consume<I_AgentDetails>,
public Singleton::Consume<I_ProxyConfiguration>
{
public:
HTTPClient() = default;
@@ -31,8 +37,8 @@ private:
std::string loadCAChainDir();
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> 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> curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
};
// LCOV_EXCL_STOP

View File

@@ -535,16 +535,16 @@ HTTPClient::getFileSSL(const URLParser &url, ofstream &out_file, const string &t
}
}
boost::asio::io_service io_service;
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
Client client(
out_file,
io_service,
ctx,
url,
message->getProxyDomain(ProxyProtocol::HTTPS),
message->getProxyPort(ProxyProtocol::HTTPS),
message->getProxyCredentials(ProxyProtocol::HTTPS),
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
proxy_config->getProxyCredentials(ProxyProtocol::HTTPS),
token
);
@@ -581,19 +581,24 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s
);
}
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
HttpsCurl ssl_curl_client(
url,
out_file,
token,
message->getProxyDomain(ProxyProtocol::HTTPS),
message->getProxyPort(ProxyProtocol::HTTPS),
message->getProxyCredentials(ProxyProtocol::HTTPS),
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
proxy_config->getProxyCredentials(ProxyProtocol::HTTPS),
cert_file_path);
ssl_curl_client.setCurlOpts();
bool connection_ok = ssl_curl_client.connect();
bool connection_ok;
if (url.getBaseURL().unpack() == "downloads.openappsec.io") {
connection_ok = ssl_curl_client.downloadOpenAppsecPackages();
} else {
ssl_curl_client.setCurlOpts();
connection_ok = ssl_curl_client.connect();
}
if (!connection_ok)
{
stringstream url_s;

View File

@@ -21,6 +21,7 @@
#include "config.h"
#include "log_generator.h"
#include "health_check_manager.h"
#include "agent_core_utilities.h"
using namespace std;
using namespace ReportIS;
@@ -145,9 +146,11 @@ private:
initCloudVendorConfig()
{
static const map<string, pair<string, int>> ip_port_defaults_map = {
{"Azure", make_pair("168.63.129.16", 8117)},
{"Aws", make_pair("", 8117)}
{"Azure", make_pair(getenv("DOCKER_RPM_ENABLED") ? "" : "168.63.129.16", 8117)},
{"Aws", make_pair("", 8117)},
{"Local", make_pair("", 8117)}
};
auto cloud_vendor_maybe = getSetting<string>("reverseProxy", "cloudVendorName");
if (cloud_vendor_maybe.ok()) {
const string cloud_vendor = cloud_vendor_maybe.unpack();
@@ -247,14 +250,63 @@ 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
nginxContainerIsRunning()
{
static const string nginx_container_name = "cp_nginx_gaia";
static const string cmd_running =
"docker ps --filter name=" + nginx_container_name + " --filter status=running";
dbgTrace(D_HEALTH_CHECK) << "Checking if the container is running with the command: " << cmd_running;
auto maybe_result = Singleton::Consume<I_ShellCmd>::by<HealthChecker>()->getExecOutput(cmd_running);
if (!maybe_result.ok()) {
dbgWarning(D_HEALTH_CHECK)
<< "Unable to get status of nginx container. return false and failing health check.";
return false;
}
return (*maybe_result).find(nginx_container_name) != string::npos;
}
void
closeCurrentSocket(I_Socket::socketFd fd, I_MainLoop::RoutineID curr_routine) {
dbgDebug(D_HEALTH_CHECK) << "Connection with client closed, client fd: " << fd;
open_connections_counter--;
i_socket->closeSocket(fd);
client_sockets_routines.erase(curr_routine);
}
void
handleConnection()
{
if (open_connections_counter >= max_connections) {
dbgDebug(D_HEALTH_CHECK)
<< "Cannot serve new client, reached maximun open connections bound which is:"
<< "Cannot serve new client, reached maximum open connections bound which is:"
<< open_connections_counter
<< "maximun allowed: "
<< "maximum allowed: "
<< max_connections;
return;
}
@@ -276,21 +328,84 @@ private:
dbgDebug(D_HEALTH_CHECK) << "Successfully accepted client, client fd: " << new_client_socket;
open_connections_counter++;
auto curr_routine = i_mainloop->addFileRoutine(
auto curr_routine = i_mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
new_client_socket,
[this] ()
{
auto curr_routine_id = i_mainloop->getCurrentRoutineId().unpack();
auto curr_client_socket = client_sockets_routines[curr_routine_id];
auto data_recieved = i_socket->receiveData(curr_client_socket, sizeof(uint8_t), false);
if (!data_recieved.ok()) {
dbgDebug(D_HEALTH_CHECK) << "Connection with client closed, client fd: " << curr_client_socket;
open_connections_counter--;
i_socket->closeSocket(curr_client_socket);
client_sockets_routines.erase(curr_routine_id);
closeCurrentSocket(curr_client_socket, curr_routine_id);
i_mainloop->stop();
}
static const string success_response =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 25\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"health check successful\r\n";
static const vector<char> success_response_buffer(success_response.begin(), success_response.end());
static const string failure_response =
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Length: 21\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"health check failed\r\n";
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()) {
dbgDebug(D_HEALTH_CHECK)
<< "nginx conatiner is running, returning the following response: "
<< success_response;
i_socket->writeData(curr_client_socket, success_response_buffer);
closeCurrentSocket(curr_client_socket, curr_routine_id);
return;
}
dbgDebug(D_HEALTH_CHECK)
<< "nginx conatiner is not running, returning the following response: "
<< failure_response;
i_socket->writeData(curr_client_socket, failure_response_buffer);
closeCurrentSocket(curr_client_socket, curr_routine_id);
},
"Health check probe connection handler",
true

View File

@@ -6,6 +6,7 @@
#include "mock/mock_time_get.h"
#include "mock/mock_socket_is.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_shell_cmd.h"
#include "health_check_manager.h"
#include "config.h"
@@ -18,6 +19,22 @@ using namespace testing;
USE_DEBUG_FLAG(D_HEALTH_CHECK);
static const string response =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 25\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"health check successful\r\n";
static const vector<char> response_buffer(response.begin(), response.end());
static const string failure_response =
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Length: 21\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"health check failed\r\n";
static const vector<char> failure_response_buffer(failure_response.begin(), failure_response.end());
class HealthCheckerTest : public testing::Test
{
public:
@@ -47,6 +64,7 @@ public:
NiceMock<MockLogging> mock_log;
AgentDetails agent_details;
StrictMock<MockSocketIS> mock_socket;
NiceMock<MockShellCmd> mock_shell_cmd;
I_Socket::socketFd server_socket = -1;
Context ctx;
ConfigComponent config;
@@ -82,7 +100,7 @@ TEST_F(HealthCheckerTest, clientConnection)
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false)
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe listener startup", false)
).WillOnce(DoAll(SaveArg<1>(&handle_probe_routine), Return(0)));
EXPECT_CALL(
@@ -95,11 +113,19 @@ TEST_F(HealthCheckerTest, clientConnection)
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
int socket = 1;
EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket));
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0));
EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector<char>()));
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillRepeatedly(Return(string("cp_nginx_gaia")));
EXPECT_CALL(mock_socket, writeData(_, response_buffer)).WillOnce(Return(true));
EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2);
health_checker.init();
handle_probe_routine();
connection_handler_routine();
@@ -168,7 +194,7 @@ TEST_F(HealthCheckerTest, connectionsLimit)
connection_handler_routine();
EXPECT_THAT(
capture_debug.str(), HasSubstr("Cannot serve new client, reached maximun open connections")
capture_debug.str(), HasSubstr("Cannot serve new client, reached maximum open connections")
);
}
@@ -194,10 +220,17 @@ TEST_F(HealthCheckerTest, disablingAfterEnabled)
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
int socket = 1;
EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket));
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0));
EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector<char>()));
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillOnce(Return(string("cp_nginx_gaia")));
EXPECT_CALL(mock_socket, writeData(_, response_buffer)).WillOnce(Return(true));
EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2);
health_checker.init();
handle_probe_routine();
@@ -242,11 +275,20 @@ TEST_F(HealthCheckerTest, changePortIpConfig)
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
int socket = 1;
int socket2 = 0;
EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket));
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0));
EXPECT_CALL(mock_socket, receiveData(_, 1, false)).Times(2).WillRepeatedly(Return(vector<char>()));
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).Times(2).WillRepeatedly(Return(string("cp_nginx_gaia")));
EXPECT_CALL(mock_socket, writeData(_, response_buffer)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2);
EXPECT_CALL(mock_socket, closeSocket(socket2));
health_checker.init();
handle_probe_routine();
connection_handler_routine();
@@ -258,3 +300,44 @@ TEST_F(HealthCheckerTest, changePortIpConfig)
setConfiguration(new_port, "Health Check", "Probe port");
connection_handler_routine();
}
TEST_F(HealthCheckerTest, FailedHealthCheck)
{
string ip = "1.2.3.4";
setConfiguration(ip, "Health Check", "Probe IP");
uint port = 11600;
setConfiguration(port, "Health Check", "Probe port");
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false)
).WillOnce(DoAll(SaveArg<1>(&handle_probe_routine), Return(0)));
EXPECT_CALL(
mock_socket,
genSocket(I_Socket::SocketType::TCP, false, true, _)
).WillRepeatedly(Return(1));
EXPECT_CALL(
mock_mainloop,
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
int socket = 1;
EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket));
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0));
EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector<char>()));
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillOnce(Return(string("")));
EXPECT_CALL(mock_socket, writeData(_, failure_response_buffer)).WillOnce(Return(true));
EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2);
health_checker.init();
handle_probe_routine();
connection_handler_routine();
connection_handler_routine();
setConfiguration(false, "Health Check", "Probe enabled");
}

View File

@@ -24,8 +24,8 @@ USE_DEBUG_FLAG(D_ORCHESTRATOR);
static inline string &
trim(string &in)
{
in.erase(in.begin(), find_if(in.begin(), in.end(), not1(ptr_fun<int, int>(isspace))));
in.erase(find_if(in.rbegin(), in.rend(), not1(ptr_fun<int, int>(isspace))).base(), in.end());
in.erase(in.begin(), find_if(in.begin(), in.end(), [] (char c) { return !isspace(c); }));
in.erase(find_if(in.rbegin(), in.rend(), [] (char c) { return !isspace(c); }).base(), in.end());
return in;
}

View File

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

View File

@@ -142,6 +142,7 @@ protected:
std::string base64Encode(const std::string &in) const;
std::string buildBasicAuthHeader(const std::string &username, const std::string &pass) const;
std::string buildOAuth2Header(const std::string &token) const;
std::string getUserEdition() const;
// This apps which the orchestrations requires them from Fog.
std::vector<std::string> required_security_apps;
@@ -266,17 +267,25 @@ private:
S2C_PARAM(std::string, agentId);
};
class PolicyVersionPatchRequest : public ClientRest
class PolicyVersionPatchRequest
{
public:
PolicyVersionPatchRequest(const std::string &_policy_version)
PolicyVersionPatchRequest(const std::string &_policy_version, const std::string &_policy_versions)
:
policy_version(_policy_version)
policy_version(_policy_version),
policy_versions(_policy_versions)
{
}
Maybe<std::string>
genJson() const
{
return "{ \"policyVersion\" :\"" + policy_version + "\", \"versions\": " + policy_versions + "}";
}
private:
C2S_LABEL_PARAM(std::string, policy_version, "policyVersion");
std::string policy_version;
std::string policy_versions;
};
class TokenRequest : public ClientRest

View File

@@ -41,7 +41,10 @@ public:
void init() override;
Maybe<void> getUpdate(CheckUpdateRequest &request) override;
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
DeclarativePolicyUtils declarative_policy_utils;

View File

@@ -54,6 +54,7 @@ public:
last_update = i_orch_status->getUpdateTime();
last_update_status = i_orch_status->getUpdateStatus();
policy_version = i_orch_status->getPolicyVersion();
waap_model_version = i_orch_status->getWaapModelVersion();
last_policy_update = i_orch_status->getLastPolicyUpdate();
last_manifest_update = i_orch_status->getLastManifestUpdate();
last_settings_update = i_orch_status->getLastSettingsUpdate();
@@ -72,6 +73,7 @@ private:
S2C_LABEL_PARAM(std::string, last_update, "Last update");
S2C_LABEL_PARAM(std::string, last_update_status, "Last update status");
S2C_LABEL_PARAM(std::string, policy_version, "Policy version");
S2C_LABEL_PARAM(std::string, waap_model_version, "AI model version");
S2C_LABEL_PARAM(std::string, last_policy_update, "Last policy update");
S2C_LABEL_PARAM(std::string, last_manifest_update, "Last manifest update");
S2C_LABEL_PARAM(std::string, last_settings_update, "Last settings update");

View File

@@ -46,7 +46,10 @@ public:
void init() override;
Maybe<void> getUpdate(CheckUpdateRequest &request) override;
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
Maybe<std::string> getNewVersion();

View File

@@ -33,7 +33,10 @@ public:
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
void setAddressExtenesion(const std::string &extension) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
std::string getChecksum(const std::string &file_path);

View File

@@ -45,6 +45,7 @@ public:
MOCK_CONST_METHOD0(getUpdateTime, const std::string&());
MOCK_CONST_METHOD0(getLastManifestUpdate, const std::string&());
MOCK_CONST_METHOD0(getPolicyVersion, const std::string&());
MOCK_CONST_METHOD0(getWaapModelVersion, const std::string&());
MOCK_CONST_METHOD0(getLastPolicyUpdate, const std::string&());
MOCK_CONST_METHOD0(getLastSettingsUpdate, const std::string&());
MOCK_CONST_METHOD0(getUpgradeMode, const std::string&());

View File

@@ -55,5 +55,11 @@ public:
MOCK_CONST_METHOD1(executeCmd, bool(const std::string &));
MOCK_CONST_METHOD1(base64Encode, std::string(const std::string &));
MOCK_CONST_METHOD1(base64Decode, std::string(const std::string &));
MOCK_CONST_METHOD2(removeDirectory, bool(const std::string &, bool delete_content));
MOCK_CONST_METHOD1(loadTenantsFromDir, void(const std::string &));
MOCK_CONST_METHOD3(
deleteVirtualTenantProfileFiles,
void(const std::string &tenant_id, const std::string &profile_id, const std::string &conf_path)
);
};
#endif // __MOCK_ORCHESTRATION_TOOLS_H__

View File

@@ -38,14 +38,16 @@ public:
MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &());
MOCK_CONST_METHOD0(getPolicyVersions, const std::string &());
MOCK_METHOD6(
updateServiceConfiguration,
bool(
Maybe<void>(
const std::string &new_policy_path,
const std::string &new_settings_path,
const std::vector<std::string> &new_data_files,
const std::string &tenant_id,
const std::string &profile_id,
const std::string &child_tenant_id,
const std::string &child_profile_id,
const bool last_iteration
)
);

View File

@@ -31,7 +31,7 @@ public:
MOCK_METHOD1(getUpdate, Maybe<void>(CheckUpdateRequest &));
MOCK_METHOD1(downloadAttributeFile, Maybe<std::string>(const GetResourceFile &));
MOCK_METHOD1(setAddressExtenesion, void(const std::string &));
MOCK_CONST_METHOD1(sendPolicyVersion, Maybe<void>(const std::string &));
MOCK_CONST_METHOD2(sendPolicyVersion, Maybe<void>(const std::string &, const std::string &));
};
#endif // __MOCK_UPDATE_COMMUNICATION_H__

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)

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

@@ -1,157 +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 __POLICY_MAKER_UTILS_H__
#define __POLICY_MAKER_UTILS_H__
#include <string>
#include <fstream>
#include <utility>
#include <sys/types.h>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "debug.h"
#include "common.h"
#include "maybe_res.h"
#include "i_orchestration_tools.h"
#include "i_shell_cmd.h"
#include "i_messaging.h"
#include "appsec_practice_section.h"
#include "ingress_data.h"
#include "settings_section.h"
#include "triggers_section.h"
#include "local_policy_common.h"
#include "exceptions_section.h"
#include "rules_config_section.h"
#include "trusted_sources_section.h"
enum class AnnotationTypes {
PRACTICE,
TRIGGER,
EXCEPTION,
WEB_USER_RES,
SOURCE_IDENTIFIERS,
TRUSTED_SOURCES,
COUNT
};
class SecurityAppsWrapper
{
public:
SecurityAppsWrapper(
const AppSecWrapper &_waap,
const TriggersWrapper &_trrigers,
const RulesConfigWrapper &_rules,
const ExceptionsWrapper &_exceptions,
const std::string &_policy_version)
:
waap(_waap),
trrigers(_trrigers),
rules(_rules),
exceptions(_exceptions),
policy_version(_policy_version) {}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
AppSecWrapper waap;
TriggersWrapper trrigers;
RulesConfigWrapper rules;
ExceptionsWrapper exceptions;
std::string policy_version;
};
class PolicyWrapper
{
public:
PolicyWrapper(
const SettingsWrapper &_settings,
const SecurityAppsWrapper &_security_apps)
:
settings(_settings),
security_apps(_security_apps) {}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
SettingsWrapper settings;
SecurityAppsWrapper security_apps;
};
class PolicyMakerUtils
:
Singleton::Consume<I_Environment>,
Singleton::Consume<I_OrchestrationTools>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_ShellCmd>
{
public:
std::string proccesSingleAppsecPolicy(
const std::string &policy_path,
const std::string &policy_version,
const std::string &local_appsec_policy_path
);
std::string proccesMultipleAppsecPolicies(
const std::map<std::string, AppsecLinuxPolicy> &appsec_policies,
const std::string &policy_version,
const std::string &local_appsec_policy_path
);
private:
std::string getPolicyName(const std::string &policy_path);
Maybe<AppsecLinuxPolicy> openPolicyAsJson(const std::string &policy_path);
void clearElementsMaps();
bool startsWith(const std::string &str, const std::string &prefix);
bool endsWith(const std::string &str, const std::string &suffix);
std::tuple<std::string, std::string, std::string> splitHostName(const std::string &host_name);
std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path);
PolicyWrapper combineElementsToPolicy(const std::string &policy_version);
void createPolicyElementsByRule(
const ParsedRule &rule,
const ParsedRule &default_rule,
const AppsecLinuxPolicy &policy,
const std::string &policy_name
);
void createPolicyElements(
const std::vector<ParsedRule> &rules,
const ParsedRule &default_rule,
const AppsecLinuxPolicy &policy,
const std::string &policy_name
);
void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const AppsecLinuxPolicy &appsec_policy);
std::map<std::string, LogTriggerSection> log_triggers;
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
std::map<std::string, InnerException> inner_exceptions;
std::map<std::string, WebAppSection> web_apps;
std::map<std::string, RulesConfigRulebase> rules_config;
std::map<std::string, UsersIdentifiersRulebase> users_identifiers;
std::map<std::string, AppSecTrustedSources> trusted_sources;
};
#endif // __POLICY_MAKER_UTILS_H__

View File

@@ -1,343 +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.
#include "k8s_policy_utils.h"
#include "namespace_data.h"
using namespace std;
USE_DEBUG_FLAG(D_NGINX_POLICY);
string
convertAnnotationKeysTostring(const AnnotationKeys &key)
{
switch (key) {
case AnnotationKeys::PolicyKey:
return "policy";
case AnnotationKeys::OpenAppsecIo:
return "openappsec.io/";
case AnnotationKeys::SyslogAddressKey:
return "syslog";
case AnnotationKeys::ModeKey:
return "mode";
default:
return "Irrelevant key";
}
}
void
K8sPolicyUtils::init()
{
env_details = Singleton::Consume<I_EnvDetails>::by<K8sPolicyUtils>();
env_type = env_details->getEnvType();
if (env_type == EnvType::K8S) {
token = env_details->getToken();
messaging = Singleton::Consume<I_Messaging>::by<K8sPolicyUtils>();
conn_flags.setFlag(MessageConnConfig::SECURE_CONN);
conn_flags.setFlag(MessageConnConfig::IGNORE_SSL_VALIDATION);
}
}
map<AnnotationKeys, string>
K8sPolicyUtils::parseIngressAnnotations(const map<string, string> &annotations) const
{
map<AnnotationKeys, string> annotations_values;
for (const pair<string, string> &annotation : annotations) {
string annotation_key = annotation.first;
string annotation_val = annotation.second;
if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::OpenAppsecIo)) != string::npos) {
if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::PolicyKey)) != string::npos) {
annotations_values[AnnotationKeys::PolicyKey] = annotation_val;
} else if (
annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::SyslogAddressKey)) != string::npos
) {
bool has_port = annotation_val.find(":");
annotations_values[AnnotationKeys::SyslogAddressKey] =
annotation_val.substr(0, annotation_val.find(":"));
annotations_values[AnnotationKeys::SyslogPortKey] =
has_port ? annotation_val.substr(annotation_val.find(":") + 1) : "";
} else if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::ModeKey)) != string::npos) {
annotations_values[AnnotationKeys::ModeKey] = annotation_val;
}
}
}
return annotations_values;
}
template<class T>
Maybe<T, string>
K8sPolicyUtils::getObjectFromCluster(const string &path) const
{
T object;
bool res = messaging->sendObject(
object,
I_Messaging::Method::GET,
"kubernetes.default.svc",
443,
conn_flags,
path,
"Authorization: Bearer " + token + "\nConnection: close"
);
if (res) return object;
return genError(string("Was not able to get object form k8s cluser in path: " + path));
}
map<AnnotationTypes, unordered_set<string>>
K8sPolicyUtils::extractElementsNames(const vector<ParsedRule> &specific_rules, const ParsedRule &default_rule) const
{
map<AnnotationTypes, unordered_set<string>> policy_elements_names;
for (const ParsedRule &specific_rule : specific_rules) {
policy_elements_names[AnnotationTypes::EXCEPTION].insert(
specific_rule.getExceptions().begin(),
specific_rule.getExceptions().end()
);
policy_elements_names[AnnotationTypes::PRACTICE].insert(
specific_rule.getPractices().begin(),
specific_rule.getPractices().end()
);
policy_elements_names[AnnotationTypes::TRIGGER].insert(
specific_rule.getLogTriggers().begin(),
specific_rule.getLogTriggers().end()
);
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(specific_rule.getCustomResponse());
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(specific_rule.getSourceIdentifiers());
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(specific_rule.getTrustedSources());
}
policy_elements_names[AnnotationTypes::EXCEPTION].insert(
default_rule.getExceptions().begin(),
default_rule.getExceptions().end()
);
policy_elements_names[AnnotationTypes::PRACTICE].insert(
default_rule.getPractices().begin(),
default_rule.getPractices().end()
);
policy_elements_names[AnnotationTypes::TRIGGER].insert(
default_rule.getLogTriggers().begin(),
default_rule.getLogTriggers().end()
);
policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(default_rule.getCustomResponse());
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(default_rule.getSourceIdentifiers());
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(default_rule.getTrustedSources());
return policy_elements_names;
}
template<class T>
vector<T>
K8sPolicyUtils::extractElementsFromCluster(
const string &crd_plural,
const unordered_set<string> &elements_names) const
{
dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural;
vector<T> elements;
for (const string &element_name : elements_names) {
dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name;
auto maybe_appsec_element = getObjectFromCluster<AppsecSpecParser<T>>(
"/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<T> appsec_element = maybe_appsec_element.unpack();
if (appsec_element.getSpec().getName() == "") {
appsec_element.setName(element_name);
}
elements.push_back(appsec_element.getSpec());
}
return elements;
}
Maybe<AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const
{
auto maybe_appsec_policy_spec = getObjectFromCluster<AppsecSpecParser<AppsecPolicySpec>>(
"/apis/openappsec.io/v1beta1/policies/" + policy_name
);
if (!maybe_appsec_policy_spec.ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve AppSec policy. Error: "
<< maybe_appsec_policy_spec.getErr();
return genError("Failed to retrieve AppSec policy. Error: " + maybe_appsec_policy_spec.getErr());
}
AppsecSpecParser<AppsecPolicySpec> appsec_policy_spec = maybe_appsec_policy_spec.unpack();
ParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule();
vector<ParsedRule> specific_rules = appsec_policy_spec.getSpec().getSpecificRules();
if (!ingress_mode.empty() && default_rule.getMode().empty()) {
default_rule.setMode(ingress_mode);
}
map<AnnotationTypes, unordered_set<string>> policy_elements_names = extractElementsNames(
specific_rules,
default_rule
);
vector<AppSecPracticeSpec> practices = extractElementsFromCluster<AppSecPracticeSpec>(
"practices",
policy_elements_names[AnnotationTypes::PRACTICE]
);
vector<AppsecTriggerSpec> log_triggers = extractElementsFromCluster<AppsecTriggerSpec>(
"logtriggers",
policy_elements_names[AnnotationTypes::TRIGGER]
);
vector<AppSecCustomResponseSpec> web_user_responses = extractElementsFromCluster<AppSecCustomResponseSpec>(
"customresponses",
policy_elements_names[AnnotationTypes::WEB_USER_RES]
);
vector<AppsecExceptionSpec> exceptions = extractElementsFromCluster<AppsecExceptionSpec>(
"exceptions",
policy_elements_names[AnnotationTypes::EXCEPTION]
);
vector<SourceIdentifierSpecWrapper> source_identifiers = extractElementsFromCluster<SourceIdentifierSpecWrapper>(
"sourcesidentifiers",
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS]
);
vector<TrustedSourcesSpec> trusted_sources = extractElementsFromCluster<TrustedSourcesSpec>(
"trustedsources",
policy_elements_names[AnnotationTypes::TRUSTED_SOURCES]
);
AppsecLinuxPolicy appsec_policy = AppsecLinuxPolicy(
appsec_policy_spec.getSpec(),
practices,
log_triggers,
web_user_responses,
exceptions,
trusted_sources,
source_identifiers
);
return appsec_policy;
}
map<string, AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPoliciesFromIngresses()
{
dbgFlow(D_LOCAL_POLICY) << "Getting all policy object from Ingresses";
map<string, AppsecLinuxPolicy> policies;
auto maybe_ingress = getObjectFromCluster<IngressData>("/apis/networking.k8s.io/v1/ingresses");
if (!maybe_ingress.ok()) {
// TBD: Error handling : INXT-31444
dbgWarning(D_LOCAL_POLICY)
<< "Failed to retrieve K8S Ingress configurations. Error: "
<< maybe_ingress.getErr();
return policies;
}
IngressData ingress = maybe_ingress.unpack();
for (const SingleIngressData &item : ingress.getItems()) {
map<AnnotationKeys, string> annotations_values = parseIngressAnnotations(
item.getMetadata().getAnnotations()
);
if (annotations_values[AnnotationKeys::PolicyKey].empty()) {
dbgInfo(D_LOCAL_POLICY) << "No policy was found in this ingress";
continue;
}
Maybe<AppsecLinuxPolicy> maybe_appsec_policy = createAppsecPolicyK8s(
annotations_values[AnnotationKeys::PolicyKey],
annotations_values[AnnotationKeys::ModeKey]
);
if (!maybe_appsec_policy.ok()) {
dbgWarning(D_LOCAL_POLICY)
<< "Failed to create appsec policy. Error: "
<< maybe_appsec_policy.getErr();
continue;
}
AppsecLinuxPolicy appsec_policy = maybe_appsec_policy.unpack();
for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
string url = rule.getHost();
for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) {
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Host data to the specific asset set:"
<< "URL: '"
<< url
<< "' uri: '"
<< uri.getPath()
<< "'";
ParsedRule ingress_rule = ParsedRule(url + uri.getPath());
appsec_policy.addSpecificRule(ingress_rule);
}
}
}
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
return 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

@@ -1,812 +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.
#include "policy_maker_utils.h"
using namespace std;
USE_DEBUG_FLAG(D_NGINX_POLICY);
void
SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("waap", waap),
cereal::make_nvp("triggers", trrigers),
cereal::make_nvp("rules", rules),
cereal::make_nvp("exceptions", exceptions),
cereal::make_nvp("version", policy_version)
);
}
void
PolicyWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
security_apps.save(out_ar);
}
string
PolicyMakerUtils::getPolicyName(const string &policy_path)
{
string policy_name;
if (policy_path.find_last_of("/") != string::npos) {
policy_name = policy_path.substr(policy_path.find_last_of("/") + 1);
} else {
policy_name = policy_path;
}
if (policy_name.find(".") != string::npos) {
return policy_name.substr(0, policy_name.find("."));
}
return policy_name;
}
Maybe<AppsecLinuxPolicy>
PolicyMakerUtils::openPolicyAsJson(const string &policy_path)
{
auto maybe_policy_as_json = Singleton::Consume<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput(
getFilesystemPathConfig() + "/bin/yq " + policy_path + " -o json"
);
if (!maybe_policy_as_json.ok()) {
dbgDebug(D_NGINX_POLICY) << "Could not convert policy from yaml to json";
return genError("Could not convert policy from yaml to json. Error: " + maybe_policy_as_json.getErr());
}
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>();
auto maybe_policy = i_orchestration_tools->jsonStringToObject<AppsecLinuxPolicy>(
maybe_policy_as_json.unpack()
);
if (!maybe_policy.ok()) {
string error = "Policy in path: " + policy_path + " was not loaded. Error: " + maybe_policy.getErr();
dbgDebug(D_NGINX_POLICY) << error;
return genError(error);
}
return maybe_policy.unpack();
}
void
PolicyMakerUtils::clearElementsMaps()
{
log_triggers.clear();
web_user_res_triggers.clear();
inner_exceptions.clear();
web_apps.clear();
rules_config.clear();
}
// LCOV_EXCL_START Reason: no test exist - needed for NGINX config
bool
PolicyMakerUtils::startsWith(const string &str, const string &prefix)
{
return str.rfind(prefix, 0) == 0;
}
bool
PolicyMakerUtils::endsWith(const string &str, const string &suffix)
{
return str.size() >= suffix.size() &&
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}
// LCOV_EXCL_STOP
tuple<string, string, string>
PolicyMakerUtils::splitHostName(const string &host_name)
{
string url = host_name;
string uri;
string port;
if (startsWith(url, "http://")) {
url = url.substr(7, url.length() - 1);
port = "80";
} else if (startsWith(url, "https://")) {
url = url.substr(8, url.length() - 1);
port = "443";
}
if (url.find("/") != string::npos) {
uri = url.substr(url.find("/"));
url = url.substr(0, url.find("/"));
} else {
uri = "";
}
if (url.find(":") != string::npos) {
port = url.substr(url.find(":") + 1, url.length() - 1);
url = url.substr(0, url.find(":"));
}
if (host_name == "*") {
url = "Any";
uri = "Any";
}
return make_tuple(url, port, uri);
}
string
PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &policy_path)
{
clearElementsMaps();
stringstream ss;
{
cereal::JSONOutputArchive ar(ss);
policy.save(ar);
}
string policy_str = ss.str();
try {
ofstream policy_file(policy_path);
policy_file << policy_str;
policy_file.close();
} catch (const ofstream::failure &e) {
dbgDebug(D_NGINX_POLICY) << "Error while writing new policy to " << policy_path << ", Error: " << e.what();
return "";
}
return policy_str;
}
map<AnnotationTypes, string>
extractAnnotationsNames(
const ParsedRule &parsed_rule,
const ParsedRule &default_rule,
const string &policy_name)
{
map<AnnotationTypes, string> rule_annotation;
string practice_annotation_name;
// TBD: support multiple practices
if (!parsed_rule.getPractices().empty() && !parsed_rule.getPractices()[0].empty()) {
practice_annotation_name = parsed_rule.getPractices()[0];
} else if (!default_rule.getPractices().empty() && !default_rule.getPractices()[0].empty()) {
practice_annotation_name = default_rule.getPractices()[0];
}
if (!practice_annotation_name.empty()) {
rule_annotation[AnnotationTypes::PRACTICE] = policy_name + "/" + practice_annotation_name;
}
string trigger_annotation_name;
// TBD: support multiple triggers
if (!parsed_rule.getLogTriggers().empty() && !parsed_rule.getLogTriggers()[0].empty()) {
trigger_annotation_name = parsed_rule.getLogTriggers()[0];
} else if (!default_rule.getLogTriggers().empty() && !default_rule.getLogTriggers()[0].empty()) {
trigger_annotation_name = default_rule.getLogTriggers()[0];
}
if (!trigger_annotation_name.empty()) {
rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name;
}
string exception_annotation_name;
// TBD: support multiple exceptions
if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) {
exception_annotation_name = parsed_rule.getExceptions()[0];
} else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) {
exception_annotation_name = default_rule.getExceptions()[0];
}
if (!exception_annotation_name.empty()) {
rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name;
}
string web_user_res_annotation_name =
parsed_rule.getCustomResponse().empty() ?
default_rule.getCustomResponse() :
parsed_rule.getCustomResponse();
if (!web_user_res_annotation_name.empty()) {
rule_annotation[AnnotationTypes::WEB_USER_RES] = policy_name + "/" + web_user_res_annotation_name;
}
string source_identifiers_annotation_name =
parsed_rule.getSourceIdentifiers().empty() ?
default_rule.getSourceIdentifiers() :
parsed_rule.getSourceIdentifiers();
if (!source_identifiers_annotation_name.empty()) {
rule_annotation[AnnotationTypes::SOURCE_IDENTIFIERS] = policy_name + "/" + source_identifiers_annotation_name;
}
string trusted_sources_annotation_name =
parsed_rule.getTrustedSources ().empty() ?
default_rule.getTrustedSources() :
parsed_rule.getTrustedSources();
if (!trusted_sources_annotation_name.empty()) {
rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name;
}
return rule_annotation;
}
template<class container_it>
container_it
extractElement(container_it begin, container_it end, const string &element_name)
{
dbgTrace(D_NGINX_POLICY) << "Tryting to find element: " << element_name;
string clean_element_name = element_name.substr(element_name.find("/") + 1);
for (container_it it = begin; it < end; it++) {
if (clean_element_name == it->getName()) {
dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was found";
return it;
}
}
dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was not found";
return end;
}
template<typename K, typename V>
vector<V>
convertMapToVector(map<K, V> map)
{
vector<V> vec;
vec.reserve(map.size());
if (map.empty()) {
return vec;
}
for (const auto &m : map) {
if (!m.first.empty()) vec.push_back(m.second);
}
return vec;
}
AppSecPracticeSpec
getAppsecPracticeSpec(const string &practice_annotation_name, const AppsecLinuxPolicy &policy)
{
auto practices_vec = policy.getAppSecPracticeSpecs();
auto practice_it = extractElement(practices_vec.begin(), practices_vec.end(), practice_annotation_name);
if (practice_it == practices_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec practice";
return AppSecPracticeSpec();
}
return *practice_it;
}
AppsecTriggerSpec
getAppsecTriggerSpec(const string &trigger_annotation_name, const AppsecLinuxPolicy &policy)
{
auto triggers_vec = policy.getAppsecTriggerSpecs();
auto trigger_it = extractElement(triggers_vec.begin(), triggers_vec.end(), trigger_annotation_name);
if (trigger_it == triggers_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trigger";
return AppsecTriggerSpec();
}
return *trigger_it;
}
AppsecExceptionSpec
getAppsecExceptionSpec(const string &exception_annotation_name, const AppsecLinuxPolicy &policy)
{
auto exceptions_vec = policy.getAppsecExceptionSpecs();
auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name);
if (exception_it == exceptions_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec exception";
return AppsecExceptionSpec();
}
return *exception_it;
}
AppSecCustomResponseSpec
getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const AppsecLinuxPolicy &policy)
{
auto custom_response_vec = policy.getAppSecCustomResponseSpecs();
auto custom_response_it = extractElement(
custom_response_vec.begin(),
custom_response_vec.end(),
custom_response_annotation_name);
if (custom_response_it == custom_response_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec custom response";
return AppSecCustomResponseSpec();
}
return *custom_response_it;
}
SourceIdentifierSpecWrapper
getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const AppsecLinuxPolicy &policy)
{
auto source_identifiers_vec = policy.getAppsecSourceIdentifierSpecs();
auto source_identifier_it = extractElement(
source_identifiers_vec.begin(),
source_identifiers_vec.end(),
source_identifiers_annotation_name);
if (source_identifier_it == source_identifiers_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec source identifier";
return SourceIdentifierSpecWrapper();
}
return *source_identifier_it;
}
TrustedSourcesSpec
getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const AppsecLinuxPolicy &policy)
{
auto trusted_sources_vec = policy.getAppsecTrustedSourceSpecs();
auto trusted_sources_it = extractElement(
trusted_sources_vec.begin(),
trusted_sources_vec.end(),
trusted_sources_annotation_name);
if (trusted_sources_it == trusted_sources_vec.end()) {
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trusted source";
return TrustedSourcesSpec();
}
return *trusted_sources_it;
}
LogTriggerSection
createLogTriggerSection(
const string &trigger_annotation_name,
const AppsecLinuxPolicy &policy)
{
AppsecTriggerSpec trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy);
string verbosity = "Standard";
string extendLoggingMinSeverity =
trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity();
bool tpDetect = trigger_spec.getAppsecTriggerLogging().isDetectEvents();
bool tpPrevent = trigger_spec.getAppsecTriggerLogging().isPreventEvents();
bool webRequests = trigger_spec.getAppsecTriggerLogging().isAllWebRequests();
bool webUrlPath = trigger_spec.getAppsecTriggerExtendedLogging().isUrlPath();
bool webUrlQuery = trigger_spec.getAppsecTriggerExtendedLogging().isUrlQuery();
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
bool logToK8sService = trigger_spec.getAppsecTriggerLogDestination().isK8SNeeded();
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
bool logToSyslog = trigger_spec.getAppsecTriggerLogDestination().isSyslogNeeded();
bool responseBody = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isResponseBody();
bool extendLogging = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isEnabled();
int cefPortNum = logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerUdpPort() : 0;
string cefIpAddress =
logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerIpv4Address() : "";
int syslogPortNum =
logToSyslog ?
trigger_spec.getAppsecTriggerLogDestination().getSyslogServerUdpPort() :
514;
string syslogIpAddress =
logToSyslog ?
trigger_spec.getAppsecTriggerLogDestination().getSyslogServerIpv4Address() :
"";
LogTriggerSection log(
trigger_annotation_name,
verbosity,
extendLoggingMinSeverity,
extendLogging,
logToAgent,
logToCef,
logToCloud,
logToK8sService,
logToSyslog,
responseBody,
tpDetect,
tpPrevent,
webBody,
webHeaders,
webRequests,
webUrlPath,
webUrlQuery,
cefPortNum,
cefIpAddress,
syslogPortNum,
syslogIpAddress,
beautify_logs
);
return log;
}
WebUserResponseTriggerSection
createWebUserResponseTriggerSection(
const string &web_user_res_annotation_name,
const AppsecLinuxPolicy &policy)
{
AppSecCustomResponseSpec web_user_res_spec = getAppsecCustomResponseSpec(web_user_res_annotation_name, policy);
string mode = web_user_res_spec.getMode();
string response_body = web_user_res_spec.getMessageBody();
string response_title = web_user_res_spec.getMessageTitle();
int response_code = web_user_res_spec.getHttpResponseCode();
WebUserResponseTriggerSection web_user_res(
web_user_res_annotation_name,
mode,
response_body,
response_code,
response_title
);
return web_user_res;
}
vector<SourcesIdentifiers>
addSourceIdentifiersToTrustedSource(
const string &source_identifeir_from_trust,
const SourceIdentifierSpec &src_ident
)
{
vector<SourcesIdentifiers> generated_trusted_json;
if (src_ident.getValues().empty()) {
generated_trusted_json.push_back(
SourcesIdentifiers(src_ident.getSourceIdentifier(), source_identifeir_from_trust)
);
} else {
for (const string &val : src_ident.getValues()) {
string src_key = src_ident.getSourceIdentifier() + ":" + val;
generated_trusted_json.push_back(SourcesIdentifiers(src_key, source_identifeir_from_trust));
}
}
return generated_trusted_json;
}
AppSecTrustedSources
createTrustedSourcesSection(
const string &treusted_sources_annotation_name,
const string &source_identifier_annotation_name,
const AppsecLinuxPolicy &policy)
{
TrustedSourcesSpec treusted_sources_spec = getAppsecTrustedSourceSpecs(treusted_sources_annotation_name, policy);
SourceIdentifierSpecWrapper source_identifiers_spec = getAppsecSourceIdentifierSpecs(
source_identifier_annotation_name,
policy
);
vector<SourcesIdentifiers> generated_trusted_json;
for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) {
for (const string &source_identifeir_from_trust : treusted_sources_spec.getSourcesIdentifiers()) {
vector<SourcesIdentifiers> tmp_trusted = addSourceIdentifiersToTrustedSource(
source_identifeir_from_trust,
src_ident
);
generated_trusted_json.insert(generated_trusted_json.end(), tmp_trusted.begin(), tmp_trusted.end());
}
}
AppSecTrustedSources treusted_sources(
treusted_sources_spec.getName(),
treusted_sources_spec.getMinNumOfSources(),
generated_trusted_json
);
return treusted_sources;
}
InnerException
createExceptionSection(
const string &exception_annotation_name,
const AppsecLinuxPolicy &policy)
{
AppsecExceptionSpec exception_spec = getAppsecExceptionSpec(exception_annotation_name, policy);
ExceptionMatch exception_match(exception_spec);
string behavior =
exception_spec.getAction() == "skip" ?
"ignore" :
exception_spec.getAction();
ExceptionBehavior exception_behavior("action", behavior);
InnerException inner_exception(exception_behavior, exception_match);
return inner_exception;
}
UsersIdentifiersRulebase
createUserIdentifiers (
const string &source_identifier_annotation_name,
const AppsecLinuxPolicy &policy,
const string &context
)
{
string jwt_identifier = "";
vector<string> jwt_identifier_values;
vector<UsersIdentifier> user_ident_vec;
SourceIdentifierSpecWrapper source_identifiers_spec = getAppsecSourceIdentifierSpecs(
source_identifier_annotation_name,
policy
);
for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) {
if (src_ident.getSourceIdentifier() == "JWTKey") {
jwt_identifier = "JWTKey";
jwt_identifier_values.insert(
jwt_identifier_values.end(),
src_ident.getValues().begin(),
src_ident.getValues().end()
);
user_ident_vec.push_back(UsersIdentifier("authorization", src_ident.getValues()));
} else {
user_ident_vec.push_back(UsersIdentifier(src_ident.getSourceIdentifier(), src_ident.getValues()));
}
}
UsersIdentifiersRulebase users_ident = UsersIdentifiersRulebase(
context,
jwt_identifier,
jwt_identifier_values,
user_ident_vec
);
return users_ident;
}
RulesConfigRulebase
createMultiRulesSections(
const string &url,
const string &uri,
const string &practice_id,
const string &practice_name,
const string &practice_type,
const string &log_trigger_name,
const string &log_trigger_id,
const string &log_trigger_type,
const string &web_user_res_vec_name,
const string &web_user_res_vec_id,
const string &web_user_res_vec_type,
const string &asset_name,
const string &exception_name,
const string &exception_id)
{
PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name);
ParametersSection exception_param = ParametersSection(exception_id, exception_name);
vector<RulesTriggerSection> triggers;
if (!log_trigger_id.empty()) {
triggers.push_back(RulesTriggerSection(log_trigger_name, log_trigger_id, log_trigger_type));
}
if (!web_user_res_vec_id.empty()) {
triggers.push_back(RulesTriggerSection(
web_user_res_vec_name,
web_user_res_vec_id,
web_user_res_vec_type)
);
}
RulesConfigRulebase rules_config = RulesConfigRulebase(
asset_name,
url,
uri,
{practice},
{exception_param},
triggers
);
return rules_config;
}
SettingsWrapper
createProfilesSection()
{
string agent_settings_key = "agent.test.policy";
string agent_settings_value = "local policy";
AgentSettingsSection agent_setting_1 = AgentSettingsSection(agent_settings_key, agent_settings_value);
SettingsRulebase settings_rulebase_1 = SettingsRulebase({agent_setting_1});
return SettingsWrapper(settings_rulebase_1);
}
PolicyWrapper
PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
{
TriggersWrapper triggers_section(
TriggersRulebase(
convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers)
)
);
ExceptionsWrapper exceptions_section({
ExceptionsRulebase(convertMapToVector(inner_exceptions))
});
AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {}));
RulesConfigWrapper rules_config_section(convertMapToVector(rules_config), convertMapToVector(users_identifiers));
SecurityAppsWrapper security_app_section = SecurityAppsWrapper(
appses_section,
triggers_section,
rules_config_section,
exceptions_section,
policy_version
);
SettingsWrapper profiles_section = createProfilesSection();
PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section);
return policy_wrapper;
}
void
PolicyMakerUtils::createPolicyElementsByRule(
const ParsedRule &rule,
const ParsedRule &default_rule,
const AppsecLinuxPolicy &policy,
const string &policy_name)
{
map<AnnotationTypes, string> rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name);
if (
!rule_annotations[AnnotationTypes::TRIGGER].empty() &&
!log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER])
) {
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] =
createLogTriggerSection(
rule_annotations[AnnotationTypes::TRIGGER],
policy
);
}
if (
!rule_annotations[AnnotationTypes::WEB_USER_RES].empty() &&
!web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES])
) {
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] =
createWebUserResponseTriggerSection(
rule_annotations[AnnotationTypes::WEB_USER_RES],
policy
);
}
if (
!rule_annotations[AnnotationTypes::EXCEPTION].empty() &&
!inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION])
) {
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] =
createExceptionSection(
rule_annotations[AnnotationTypes::EXCEPTION],
policy
);
}
if (
!rule_annotations[AnnotationTypes::TRUSTED_SOURCES].empty() &&
!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty() &&
!trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES])
) {
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] =
createTrustedSourcesSection(
rule_annotations[AnnotationTypes::TRUSTED_SOURCES],
rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS],
policy
);
}
if (
!rule_annotations[AnnotationTypes::PRACTICE].empty() &&
!web_apps.count(rule_annotations[AnnotationTypes::PRACTICE])
) {
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] =
createTrustedSourcesSection(
rule_annotations[AnnotationTypes::TRUSTED_SOURCES],
rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS],
policy
);
}
if (!rule_annotations[AnnotationTypes::PRACTICE].empty()) {
string practice_id = "";
try {
practice_id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
//TBD: return Maybe as part of future error handling
}
tuple<string, string, string> splited_host_name = splitHostName(rule.getHost());
string full_url = rule.getHost() == "*"
? "Any"
: rule.getHost();
RulesConfigRulebase rule_config = createMultiRulesSections(
std::get<0>(splited_host_name),
std::get<2>(splited_host_name),
practice_id,
rule_annotations[AnnotationTypes::PRACTICE],
"WebApplication",
rule_annotations[AnnotationTypes::TRIGGER],
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(),
"log",
rule_annotations[AnnotationTypes::WEB_USER_RES],
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(),
"WebUserResponse",
full_url,
rule_annotations[AnnotationTypes::EXCEPTION],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId()
);
rules_config[rule_config.getAssetName()] = rule_config;
if (!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty()) {
UsersIdentifiersRulebase user_identifiers = createUserIdentifiers(
rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS],
policy,
rule_config.getContext()
);
users_identifiers[rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS]] = user_identifiers;
}
if (!web_apps.count(rule_annotations[AnnotationTypes::PRACTICE])) {
WebAppSection web_app = WebAppSection(
full_url == "Any" ? "" : full_url,
rule_config.getAssetId(),
rule_config.getAssetName(),
rule_config.getAssetId(),
rule_config.getAssetName(),
practice_id,
rule_annotations[AnnotationTypes::PRACTICE],
getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy),
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
rule.getMode(),
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]]
);
web_apps[rule_annotations[AnnotationTypes::PRACTICE]] = web_app;
}
}
}
void
PolicyMakerUtils::createPolicyElements(
const vector<ParsedRule> &rules,
const ParsedRule &default_rule,
const AppsecLinuxPolicy &policy,
const string &policy_name)
{
for (const ParsedRule &rule : rules) {
createPolicyElementsByRule(rule, default_rule, policy, policy_name);
}
}
void
PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, const AppsecLinuxPolicy &appsec_policy)
{
dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name;
ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
// add default rule to policy
createPolicyElementsByRule(default_rule, default_rule, appsec_policy, policy_name);
vector<ParsedRule> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
createPolicyElements(specific_rules, default_rule, appsec_policy, policy_name);
}
string
PolicyMakerUtils::proccesSingleAppsecPolicy(
const string &policy_path,
const string &policy_version,
const string &local_appsec_policy_path)
{
Maybe<AppsecLinuxPolicy> maybe_policy = openPolicyAsJson(policy_path);
if (!maybe_policy.ok()){
dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr();
return "";
}
createAgentPolicyFromAppsecPolicy(getPolicyName(policy_path), maybe_policy.unpack());
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
return dumpPolicyToFile(
policy_wrapper,
local_appsec_policy_path
);
}
string
PolicyMakerUtils::proccesMultipleAppsecPolicies(
const map<string, AppsecLinuxPolicy> &appsec_policies,
const string &policy_version,
const string &local_appsec_policy_path)
{
for (const auto &appsec_policy : appsec_policies) {
createAgentPolicyFromAppsecPolicy(appsec_policy.first, appsec_policy.second);
}
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
return dumpPolicyToFile(
policy_wrapper,
local_appsec_policy_path
);
}

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