mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-30 03:34:26 +03:00
Nov_12_2023-Dev
This commit is contained in:
@@ -20,4 +20,5 @@ add_library(local_policy_mgmt_gen
|
||||
new_exceptions.cc
|
||||
access_control_practice.cc
|
||||
configmaps.cc
|
||||
reverse_proxy_section.cc
|
||||
)
|
||||
|
@@ -316,7 +316,7 @@ 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)
|
||||
@@ -368,7 +368,7 @@ AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
AppSecOverride::AppSecOverride(const InnerException &parsed_exceptions)
|
||||
:
|
||||
:
|
||||
id(parsed_exceptions.getBehaviorId()),
|
||||
parsed_match(parsed_exceptions.getMatch())
|
||||
{
|
||||
@@ -413,7 +413,7 @@ WebAppSection::WebAppSection(
|
||||
const string &default_mode,
|
||||
const AppSecTrustedSources &parsed_trusted_sources,
|
||||
const vector<InnerException> &parsed_exceptions)
|
||||
:
|
||||
:
|
||||
application_urls(_application_urls),
|
||||
asset_id(_asset_id),
|
||||
asset_name(_asset_name),
|
||||
@@ -460,7 +460,7 @@ WebAppSection::WebAppSection(
|
||||
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),
|
||||
@@ -477,6 +477,7 @@ WebAppSection::WebAppSection(
|
||||
{
|
||||
web_attack_mitigation = true;
|
||||
web_attack_mitigation_action =
|
||||
web_attack_mitigation_mode != "Prevent" ? "Transparent" :
|
||||
web_attack_mitigation_severity == "critical" ? "low" :
|
||||
web_attack_mitigation_severity == "high" ? "balanced" :
|
||||
web_attack_mitigation_severity == "medium" ? "high" :
|
||||
@@ -584,6 +585,9 @@ ParsedRule::load(cereal::JSONInputArchive &archive_in)
|
||||
parseAppsecJSONKey<string>("custom-response", custom_response, archive_in);
|
||||
parseAppsecJSONKey<string>("source-identifiers", source_identifiers, archive_in);
|
||||
parseAppsecJSONKey<string>("trusted-sources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<string>("upstream", rpm_upstream, archive_in);
|
||||
parseAppsecJSONKey<string>("rp-settings", rpm_settings, archive_in);
|
||||
parseAppsecJSONKey<bool>("ssl", rpm_is_ssl, archive_in);
|
||||
try {
|
||||
archive_in(cereal::make_nvp("host", host));
|
||||
} catch (const cereal::Exception &e)
|
||||
@@ -620,6 +624,24 @@ ParsedRule::getMode() const
|
||||
return mode;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::rpmGetUpstream() const
|
||||
{
|
||||
return rpm_upstream;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
ParsedRule::rpmGetRPSettings() const
|
||||
{
|
||||
return rpm_settings;
|
||||
}
|
||||
|
||||
bool
|
||||
ParsedRule::rpmIsHttps() const
|
||||
{
|
||||
return rpm_is_ssl;
|
||||
}
|
||||
|
||||
void
|
||||
ParsedRule::setHost(const string &_host)
|
||||
{
|
||||
@@ -691,6 +713,7 @@ AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading Appsec Linux Policy";
|
||||
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
|
||||
parseAppsecJSONKey<vector<RPMSettings>>("rp-settings", rpm_settings, 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);
|
||||
@@ -745,6 +768,13 @@ AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
|
||||
const vector<RPMSettings> &
|
||||
AppsecLinuxPolicy::rpmGetRPSettings() const
|
||||
{
|
||||
return rpm_settings;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecLinuxPolicy::addSpecificRule(const ParsedRule &_rule)
|
||||
{
|
||||
|
@@ -304,11 +304,13 @@ ExceptionMatch::getMatch() const
|
||||
ExceptionBehavior::ExceptionBehavior(const string &_value)
|
||||
{
|
||||
key = _value == "suppressLog" ? "log" : "action";
|
||||
value = key_to_action.at(_value);
|
||||
try {
|
||||
value = key_to_action.at(_value);
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what();
|
||||
} catch (std::exception &e) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Failed to find exception name: " << _value << ". Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "triggers_section.h"
|
||||
#include "exceptions_section.h"
|
||||
#include "trusted_sources_section.h"
|
||||
#include "reverse_proxy_section.h"
|
||||
#include "new_practice.h"
|
||||
|
||||
class AppSecWebBotsURI
|
||||
@@ -148,7 +149,7 @@ public:
|
||||
PracticeAdvancedConfig() {}
|
||||
|
||||
PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec)
|
||||
:
|
||||
:
|
||||
http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()),
|
||||
http_illegal_methods_allowed(0),
|
||||
http_request_body_max_size(parsed_appsec_spec.getWebAttacks().getMaxBodySizeKb()),
|
||||
@@ -162,7 +163,7 @@ public:
|
||||
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),
|
||||
@@ -186,7 +187,7 @@ class TriggersInWaapSection
|
||||
{
|
||||
public:
|
||||
TriggersInWaapSection(const LogTriggerSection &log_section)
|
||||
:
|
||||
:
|
||||
trigger_type("log"),
|
||||
id(log_section.getTriggerId()),
|
||||
name(log_section.getTriggerName()),
|
||||
@@ -241,13 +242,13 @@ public:
|
||||
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;
|
||||
|
||||
@@ -278,20 +279,20 @@ public:
|
||||
);
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
@@ -331,7 +332,7 @@ public:
|
||||
const std::string &_web_attack_mitigation_mode,
|
||||
bool _web_attack_mitigation,
|
||||
const PracticeAdvancedConfig &_practice_advanced_config)
|
||||
:
|
||||
:
|
||||
application_urls(_application_urls),
|
||||
asset_id(_asset_id),
|
||||
asset_name(_asset_name),
|
||||
@@ -345,7 +346,7 @@ public:
|
||||
web_attack_mitigation_mode(_web_attack_mitigation_mode),
|
||||
web_attack_mitigation(_web_attack_mitigation),
|
||||
practice_advanced_config(_practice_advanced_config)
|
||||
{}
|
||||
{}
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
@@ -371,7 +372,7 @@ public:
|
||||
AppSecRulebase(
|
||||
std::vector<WebAppSection> _webApplicationPractices,
|
||||
std::vector<WebAPISection> _webAPIPractices)
|
||||
:
|
||||
:
|
||||
webApplicationPractices(_webApplicationPractices),
|
||||
webAPIPractices(_webAPIPractices) {}
|
||||
|
||||
@@ -387,7 +388,7 @@ class AppSecWrapper
|
||||
{
|
||||
public:
|
||||
AppSecWrapper(const AppSecRulebase &_app_sec)
|
||||
:
|
||||
:
|
||||
app_sec_rulebase(_app_sec)
|
||||
{}
|
||||
|
||||
@@ -409,6 +410,9 @@ public:
|
||||
const std::vector<std::string> & getPractices() const;
|
||||
const std::string & getHost() const;
|
||||
const std::string & getMode() const;
|
||||
const std::string &rpmGetUpstream() const;
|
||||
const std::string &rpmGetRPSettings() const;
|
||||
bool rpmIsHttps() const;
|
||||
void setHost(const std::string &_host);
|
||||
void setMode(const std::string &_mode);
|
||||
const std::string & getCustomResponse() const;
|
||||
@@ -424,6 +428,9 @@ private:
|
||||
std::string custom_response;
|
||||
std::string source_identifiers;
|
||||
std::string trusted_sources;
|
||||
std::string rpm_upstream;
|
||||
std::string rpm_settings;
|
||||
bool rpm_is_ssl = false;
|
||||
};
|
||||
|
||||
class AppsecPolicySpec : Singleton::Consume<I_Environment>
|
||||
@@ -453,7 +460,7 @@ public:
|
||||
const std::vector<AppsecException> &_exceptions,
|
||||
const std::vector<TrustedSourcesSpec> &_trusted_sources,
|
||||
const std::vector<SourceIdentifierSpecWrapper> &_sources_identifiers)
|
||||
:
|
||||
:
|
||||
policies(_policies),
|
||||
practices(_practices),
|
||||
log_triggers(_log_triggers),
|
||||
@@ -471,6 +478,7 @@ public:
|
||||
const std::vector<AppsecException> & getAppsecExceptions() const;
|
||||
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
|
||||
const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
|
||||
const std::vector<RPMSettings> &rpmGetRPSettings() const;
|
||||
void addSpecificRule(const ParsedRule &_rule);
|
||||
|
||||
private:
|
||||
@@ -481,6 +489,7 @@ private:
|
||||
std::vector<AppsecException> exceptions;
|
||||
std::vector<TrustedSourcesSpec> trusted_sources;
|
||||
std::vector<SourceIdentifierSpecWrapper> sources_identifiers;
|
||||
std::vector<RPMSettings> rpm_settings;
|
||||
};
|
||||
|
||||
#endif // __APPSEC_PRACTICE_SECTION_H__
|
||||
|
@@ -50,7 +50,7 @@ static const std::unordered_map<std::string, TriggerType> string_to_trigger_type
|
||||
|
||||
static const std::unordered_map<std::string, std::string> key_to_practices_val = {
|
||||
{ "prevent-learn", "Prevent"},
|
||||
{ "detect-learn", "Detect"},
|
||||
{ "detect-learn", "Learn"},
|
||||
{ "prevent", "Prevent"},
|
||||
{ "detect", "Detect"},
|
||||
{ "inactive", "Inactive"}
|
||||
@@ -70,9 +70,9 @@ parseAppsecJSONKey(
|
||||
archive_in.setNextName(nullptr);
|
||||
value = default_value;
|
||||
dbgDebug(D_LOCAL_POLICY)
|
||||
<< "Could not parse the required key. Key: "
|
||||
<< "Could not parse the required key. Key: \""
|
||||
<< key_name
|
||||
<< ", Error: "
|
||||
<< "\", Error: "
|
||||
<< e.what();
|
||||
}
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ public:
|
||||
trusted_sources(_trusted_sources),
|
||||
sources_identifiers(_sources_identifiers) {}
|
||||
// LCOV_EXCL_STOP
|
||||
void serialize(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const NewAppsecPolicySpec & getAppsecPolicySpec() const;
|
||||
const std::vector<NewAppSecPracticeSpec> & getAppSecPracticeSpecs() const;
|
||||
|
@@ -147,8 +147,8 @@ public:
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
FileSecurityProtectionsSection(
|
||||
int _file_size_limit,
|
||||
int _archive_file_size_limit,
|
||||
uint64_t _file_size_limit,
|
||||
uint64_t _archive_file_size_limit,
|
||||
bool _allow_files_without_name,
|
||||
bool _required_file_size_limit,
|
||||
bool _required_archive_extraction,
|
||||
@@ -171,8 +171,8 @@ public:
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
int file_size_limit;
|
||||
int archive_file_size_limit;
|
||||
uint64_t file_size_limit;
|
||||
uint64_t archive_file_size_limit;
|
||||
bool allow_files_without_name;
|
||||
bool required_file_size_limit;
|
||||
bool required_archive_extraction;
|
||||
@@ -233,13 +233,13 @@ class NewFileSecurityArchiveInspection
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
int getArchiveFileSizeLimit() const;
|
||||
uint64_t getArchiveFileSizeLimit() const;
|
||||
bool getrequiredArchiveExtraction() const;
|
||||
const std::string & getMultiLevelArchiveAction() const;
|
||||
const std::string & getUnopenedArchiveAction() const;
|
||||
|
||||
private:
|
||||
int scan_max_file_size;
|
||||
uint64_t scan_max_file_size;
|
||||
bool extract_archive_files;
|
||||
std::string scan_max_file_size_unit;
|
||||
std::string archived_files_within_archived_files;
|
||||
@@ -251,11 +251,11 @@ class NewFileSecurityLargeFileInspection
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
int getFileSizeLimit() const;
|
||||
uint64_t getFileSizeLimit() const;
|
||||
const std::string & getFileSizeLimitAction() const;
|
||||
|
||||
private:
|
||||
int file_size_limit;
|
||||
uint64_t file_size_limit;
|
||||
std::string file_size_limit_unit;
|
||||
std::string files_exceeding_size_limit_action;
|
||||
};
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "trusted_sources_section.h"
|
||||
#include "new_appsec_linux_policy.h"
|
||||
#include "access_control_practice.h"
|
||||
#include "reverse_proxy_section.h"
|
||||
|
||||
enum class AnnotationTypes {
|
||||
PRACTICE,
|
||||
@@ -109,11 +110,6 @@ private:
|
||||
};
|
||||
|
||||
class PolicyMakerUtils
|
||||
:
|
||||
Singleton::Consume<I_Environment>,
|
||||
Singleton::Consume<I_OrchestrationTools>,
|
||||
Singleton::Consume<I_Messaging>,
|
||||
Singleton::Consume<I_ShellCmd>
|
||||
{
|
||||
public:
|
||||
std::string proccesSingleAppsecPolicy(
|
||||
@@ -206,6 +202,7 @@ private:
|
||||
createThreatPreventionPracticeSections(
|
||||
const std::string &asset_name,
|
||||
const std::string &url,
|
||||
const std::string &port,
|
||||
const std::string &uri,
|
||||
const std::string &default_mode,
|
||||
const V1beta2AppsecLinuxPolicy &policy,
|
||||
@@ -231,6 +228,11 @@ private:
|
||||
template<class T, class R>
|
||||
void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const T &appsec_policy);
|
||||
|
||||
void rpmBuildNginxServers(const AppsecLinuxPolicy &policy);
|
||||
void rpmReportInfo(const std::string &msg);
|
||||
void rpmReportError(const std::string &msg);
|
||||
|
||||
std::string policy_version_name;
|
||||
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;
|
||||
|
@@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __REVERSE_PROXY_SECTION_H__
|
||||
#define __REVERSE_PROXY_SECTION_H__
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "agent_core_utilities.h"
|
||||
#include "i_shell_cmd.h"
|
||||
|
||||
class ParsedRule;
|
||||
|
||||
class RPMSettings
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getName() const;
|
||||
std::string applySettings(const std::string &server_content) const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string host_hdr = "$host";
|
||||
std::string dns_resolver = "127.0.0.11";
|
||||
};
|
||||
|
||||
class ReverseProxyBuilder
|
||||
{
|
||||
public:
|
||||
static void init();
|
||||
|
||||
static Maybe<void> addNginxServerLocation(
|
||||
std::string location,
|
||||
const std::string &host,
|
||||
const ParsedRule &rule,
|
||||
const RPMSettings &rp_settings);
|
||||
|
||||
static Maybe<void> createNewNginxServer(
|
||||
const std::string &host,
|
||||
const ParsedRule &rule,
|
||||
const RPMSettings &rp_settings);
|
||||
|
||||
static std::string replaceTemplate(
|
||||
const std::string &content,
|
||||
const boost::regex &nginx_directive_template,
|
||||
const std::string &value);
|
||||
|
||||
static Maybe<void> reloadNginx();
|
||||
|
||||
private:
|
||||
static Maybe<void> createSSLNginxServer(const std::string &host, const RPMSettings &rp_settings);
|
||||
static Maybe<void> createHTTPNginxServer(const std::string &host, const RPMSettings &rp_settings);
|
||||
|
||||
static Maybe<std::string> getTemplateContent(const std::string &nginx_template_name);
|
||||
};
|
||||
#endif // __REVERSE_PROXY_SECTION_H__
|
@@ -90,6 +90,7 @@ public:
|
||||
RulesConfigRulebase(
|
||||
const std::string &_name,
|
||||
const std::string &_url,
|
||||
const std::string &_port,
|
||||
const std::string &_uri,
|
||||
std::vector<PracticeSection> _practices,
|
||||
std::vector<ParametersSection> _parameters,
|
||||
|
@@ -55,9 +55,7 @@ const static string default_local_mgmt_policy_path = "/conf/local_policy.yaml";
|
||||
|
||||
class LocalPolicyMgmtGenerator::Impl
|
||||
:
|
||||
public Singleton::Provide<I_LocalPolicyMgmtGen>::From<LocalPolicyMgmtGenerator>,
|
||||
public Singleton::Consume<I_MainLoop>,
|
||||
public Singleton::Consume<I_EnvDetails>
|
||||
public Singleton::Provide<I_LocalPolicyMgmtGen>::From<LocalPolicyMgmtGenerator>
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -111,7 +109,6 @@ public:
|
||||
|
||||
private:
|
||||
PolicyMakerUtils policy_maker_utils;
|
||||
|
||||
};
|
||||
|
||||
LocalPolicyMgmtGenerator::LocalPolicyMgmtGenerator()
|
||||
|
@@ -70,3 +70,31 @@ V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule)
|
||||
policies.addSpecificRule(_rule);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
V1beta2AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgInfo(D_LOCAL_POLICY) << "Loading Appsec V1Beta2 Linux Policy";
|
||||
|
||||
// Check for the presence of "apiVersion" key, present only from V1Beta2
|
||||
string api_version;
|
||||
archive_in(cereal::make_nvp("apiVersion", api_version));
|
||||
if (api_version != "v1beta2") throw cereal::Exception("Failed to parse JSON as v1Beta2 version");
|
||||
|
||||
parseAppsecJSONKey<NewAppsecPolicySpec>("policies", policies, archive_in);
|
||||
parseAppsecJSONKey<vector<NewAppSecPracticeSpec>>(
|
||||
"threatPreventionPractices",
|
||||
threat_prevection_practices,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<vector<AccessControlPracticeSpec>>(
|
||||
"accessControlPractices",
|
||||
access_control_practices,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<vector<NewAppsecLogTrigger>>("logTriggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<vector<NewAppSecCustomResponse>>("customResponse", custom_responses, archive_in);
|
||||
parseAppsecJSONKey<vector<NewAppsecException>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<vector<NewTrustedSourcesSpec>>("trustedSources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<vector<NewSourcesIdentifiers>>("sourcesIdentifiers", sources_identifiers, archive_in);
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ void
|
||||
NewAppsecException::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception";
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in, "exception");
|
||||
parseAppsecJSONKey<string>("action", action, archive_in);
|
||||
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
|
||||
if (valid_actions.count(action) == 0) {
|
||||
|
@@ -42,7 +42,7 @@ static const std::unordered_map<std::string, std::string> key_to_mode_val = {
|
||||
{ "detect", "Detect"},
|
||||
{ "inactive", "Inactive"}
|
||||
};
|
||||
static const std::unordered_map<std::string, int> unit_to_int = {
|
||||
static const std::unordered_map<std::string, uint64_t> unit_to_int = {
|
||||
{ "bytes", 1},
|
||||
{ "KB", 1024},
|
||||
{ "MB", 1048576},
|
||||
@@ -631,8 +631,8 @@ NewIntrusionPrevention::getMode() const
|
||||
}
|
||||
|
||||
FileSecurityProtectionsSection::FileSecurityProtectionsSection(
|
||||
int _file_size_limit,
|
||||
int _archive_file_size_limit,
|
||||
uint64_t _file_size_limit,
|
||||
uint64_t _archive_file_size_limit,
|
||||
bool _allow_files_without_name,
|
||||
bool _required_file_size_limit,
|
||||
bool _required_archive_extraction,
|
||||
@@ -720,7 +720,7 @@ 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<uint64_t>("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)
|
||||
@@ -749,7 +749,7 @@ NewFileSecurityArchiveInspection::load(cereal::JSONInputArchive &archive_in)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
uint64_t
|
||||
NewFileSecurityArchiveInspection::getArchiveFileSizeLimit() const
|
||||
{
|
||||
if (unit_to_int.find(scan_max_file_size_unit) == unit_to_int.end()) {
|
||||
@@ -784,7 +784,7 @@ 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<uint64_t>("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)
|
||||
@@ -803,7 +803,7 @@ NewFileSecurityLargeFileInspection::load(cereal::JSONInputArchive &archive_in)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
uint64_t
|
||||
NewFileSecurityLargeFileInspection::getFileSizeLimit() const
|
||||
{
|
||||
if (unit_to_int.find(file_size_limit_unit) == unit_to_int.end()) {
|
||||
|
@@ -64,7 +64,7 @@ void
|
||||
Identifier::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading source identifiers spec";
|
||||
parseAppsecJSONKey<string>("sourceIdentifier", identifier, archive_in);
|
||||
parseAppsecJSONKey<string>("identifier", identifier, archive_in);
|
||||
if (valid_identifiers.count(identifier) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec identifier invalid: " << identifier;
|
||||
}
|
||||
|
@@ -13,6 +13,11 @@
|
||||
|
||||
#include "policy_maker_utils.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "local_policy_mgmt_gen.h"
|
||||
#include "log_generator.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_POLICY);
|
||||
@@ -58,7 +63,7 @@ template<class T>
|
||||
Maybe<T>
|
||||
PolicyMakerUtils::openFileAsJson(const string &path)
|
||||
{
|
||||
auto maybe_file_as_json = Singleton::Consume<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput(
|
||||
auto maybe_file_as_json = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(
|
||||
getFilesystemPathConfig() + "/bin/yq " + path + " -o json"
|
||||
);
|
||||
|
||||
@@ -67,7 +72,7 @@ PolicyMakerUtils::openFileAsJson(const string &path)
|
||||
return genError("Could not convert policy from yaml to json. Error: " + maybe_file_as_json.getErr());
|
||||
}
|
||||
|
||||
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>();
|
||||
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalPolicyMgmtGenerator>();
|
||||
auto maybe_file = i_orchestration_tools->jsonStringToObject<T>(
|
||||
maybe_file_as_json.unpack()
|
||||
);
|
||||
@@ -136,10 +141,11 @@ PolicyMakerUtils::splitHostName(const string &host_name)
|
||||
url = url.substr(0, url.find(":"));
|
||||
}
|
||||
|
||||
if (host_name == "*") {
|
||||
if (host_name == "*" || host_name == "*:*") {
|
||||
url = "Any";
|
||||
uri = "Any";
|
||||
}
|
||||
|
||||
return make_tuple(url, port, uri);
|
||||
}
|
||||
|
||||
@@ -323,6 +329,7 @@ extractAnnotationsNames<NewParsedRule>(
|
||||
if (!trusted_sources_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name;
|
||||
}
|
||||
|
||||
return rule_annotation;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
@@ -451,6 +458,23 @@ getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const
|
||||
return *custom_response_it;
|
||||
}
|
||||
|
||||
template<class T, class R>
|
||||
R
|
||||
rpmGetAppsecRPSettingSpec(const string &rp_settings_name, const T &policy)
|
||||
{
|
||||
auto rp_settings_vec = policy.rpmGetRPSettings();
|
||||
auto rp_settings_it = extractElement(
|
||||
rp_settings_vec.begin(),
|
||||
rp_settings_vec.end(),
|
||||
rp_settings_name);
|
||||
|
||||
if (rp_settings_it == rp_settings_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec RP Settings";
|
||||
return R();
|
||||
}
|
||||
return *rp_settings_it;
|
||||
}
|
||||
|
||||
template<class T, class R>
|
||||
R
|
||||
getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const T &policy)
|
||||
@@ -843,6 +867,7 @@ createUserIdentifiers<V1beta2AppsecLinuxPolicy>(
|
||||
RulesConfigRulebase
|
||||
createMultiRulesSections(
|
||||
const string &url,
|
||||
const string &port,
|
||||
const string &uri,
|
||||
const string &practice_id,
|
||||
const string &practice_name,
|
||||
@@ -878,6 +903,7 @@ createMultiRulesSections(
|
||||
RulesConfigRulebase rules_config = RulesConfigRulebase(
|
||||
asset_name,
|
||||
url,
|
||||
port,
|
||||
uri,
|
||||
{practice},
|
||||
exceptions_result,
|
||||
@@ -890,6 +916,7 @@ createMultiRulesSections(
|
||||
RulesConfigRulebase
|
||||
createMultiRulesSections(
|
||||
const string &url,
|
||||
const string &port,
|
||||
const string &uri,
|
||||
const string &practice_id,
|
||||
const string &practice_name,
|
||||
@@ -907,7 +934,8 @@ createMultiRulesSections(
|
||||
const string &exception_name,
|
||||
const vector<InnerException> &exceptions)
|
||||
{
|
||||
ParametersSection exception_param = ParametersSection(exceptions[0].getBehaviorId(), exception_name);
|
||||
string behaviorId = exceptions.empty() ? "" : exceptions[0].getBehaviorId();
|
||||
ParametersSection exception_param = ParametersSection(behaviorId, exception_name);
|
||||
|
||||
vector<PracticeSection> practices;
|
||||
if (!practice_id.empty()) {
|
||||
@@ -934,6 +962,7 @@ createMultiRulesSections(
|
||||
RulesConfigRulebase rules_config = RulesConfigRulebase(
|
||||
asset_name,
|
||||
url,
|
||||
port,
|
||||
uri,
|
||||
practices,
|
||||
{exception_param},
|
||||
@@ -983,7 +1012,7 @@ PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, const st
|
||||
auto snort_scriipt_path = getFilesystemPathConfig() + "/scripts/snort_to_ips_local.py";
|
||||
auto cmd = "python " + snort_scriipt_path + " " + path + ".rule " + path + ".out " + path + ".err";
|
||||
|
||||
auto res = Singleton::Consume<I_ShellCmd>::by<PolicyMakerUtils>()->getExecOutput(cmd);
|
||||
auto res = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(cmd);
|
||||
|
||||
if (!res.ok()) {
|
||||
dbgWarning(D_LOCAL_POLICY) << res.getErr();
|
||||
@@ -996,7 +1025,7 @@ PolicyMakerUtils::createSnortProtecionsSection(const string &file_name, const st
|
||||
return;
|
||||
}
|
||||
|
||||
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PolicyMakerUtils>();
|
||||
auto i_orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalPolicyMgmtGenerator>();
|
||||
i_orchestration_tools->removeFile(path + ".rule");
|
||||
i_orchestration_tools->removeFile(path + ".out");
|
||||
i_orchestration_tools->removeFile(path + ".err");
|
||||
@@ -1153,12 +1182,15 @@ void
|
||||
PolicyMakerUtils::createThreatPreventionPracticeSections(
|
||||
const string &asset_name,
|
||||
const string &url,
|
||||
const string &port,
|
||||
const string &uri,
|
||||
const string &default_mode,
|
||||
const V1beta2AppsecLinuxPolicy &policy,
|
||||
map<AnnotationTypes, string> &rule_annotations)
|
||||
{
|
||||
if (rule_annotations[AnnotationTypes::PRACTICE].empty()) {
|
||||
if (rule_annotations[AnnotationTypes::PRACTICE].empty() ||
|
||||
web_apps.count(asset_name)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
string practice_id = "";
|
||||
@@ -1170,6 +1202,7 @@ PolicyMakerUtils::createThreatPreventionPracticeSections(
|
||||
|
||||
RulesConfigRulebase rule_config = createMultiRulesSections(
|
||||
url,
|
||||
port,
|
||||
uri,
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
@@ -1353,7 +1386,14 @@ PolicyMakerUtils::createPolicyElementsByRule(
|
||||
);
|
||||
}
|
||||
|
||||
if (!rule_annotations[AnnotationTypes::PRACTICE].empty()) {
|
||||
string full_url = rule.getHost() == "*" || rule.getHost() == "*:*"
|
||||
? "Any"
|
||||
: rule.getHost();
|
||||
|
||||
|
||||
if (!rule_annotations[AnnotationTypes::PRACTICE].empty() &&
|
||||
!web_apps.count(full_url)
|
||||
) {
|
||||
string practice_id = "";
|
||||
try {
|
||||
practice_id = to_string(boost::uuids::random_generator()());
|
||||
@@ -1362,12 +1402,10 @@ PolicyMakerUtils::createPolicyElementsByRule(
|
||||
}
|
||||
|
||||
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<1>(splited_host_name),
|
||||
std::get<2>(splited_host_name),
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
@@ -1426,7 +1464,9 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
dbgTrace(D_LOCAL_POLICY) << "Creating policy elements from version V1beta2";
|
||||
map<AnnotationTypes, string> rule_annotations =
|
||||
extractAnnotationsNames<NewParsedRule>(rule, default_rule, policy_name);
|
||||
|
||||
if (
|
||||
rule_annotations.count(AnnotationTypes::TRIGGER) > 0 &&
|
||||
!rule_annotations[AnnotationTypes::TRIGGER].empty() &&
|
||||
!log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER])
|
||||
) {
|
||||
@@ -1438,6 +1478,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
}
|
||||
|
||||
if (
|
||||
rule_annotations.count(AnnotationTypes::WEB_USER_RES) > 0 &&
|
||||
!rule_annotations[AnnotationTypes::WEB_USER_RES].empty() &&
|
||||
!web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES])
|
||||
) {
|
||||
@@ -1449,6 +1490,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
}
|
||||
|
||||
if (
|
||||
rule_annotations.count(AnnotationTypes::EXCEPTION) > 0 &&
|
||||
!rule_annotations[AnnotationTypes::EXCEPTION].empty() &&
|
||||
!inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION])
|
||||
) {
|
||||
@@ -1460,6 +1502,8 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
}
|
||||
|
||||
if (
|
||||
rule_annotations.count(AnnotationTypes::TRUSTED_SOURCES) > 0 &&
|
||||
rule_annotations.count(AnnotationTypes::SOURCE_IDENTIFIERS) > 0 &&
|
||||
!rule_annotations[AnnotationTypes::TRUSTED_SOURCES].empty() &&
|
||||
!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty() &&
|
||||
!trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES])
|
||||
@@ -1473,6 +1517,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
}
|
||||
|
||||
if (
|
||||
rule_annotations.count(AnnotationTypes::PRACTICE) > 0 &&
|
||||
!rule_annotations[AnnotationTypes::PRACTICE].empty() &&
|
||||
!web_apps.count(rule_annotations[AnnotationTypes::PRACTICE])
|
||||
) {
|
||||
@@ -1484,7 +1529,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
);
|
||||
}
|
||||
|
||||
string full_url = rule.getHost() == "*"
|
||||
string full_url = rule.getHost() == "*" || rule.getHost() == "*:*"
|
||||
? "Any"
|
||||
: rule.getHost();
|
||||
tuple<string, string, string> splited_host_name = splitHostName(rule.getHost());
|
||||
@@ -1501,6 +1546,7 @@ PolicyMakerUtils::createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsed
|
||||
createThreatPreventionPracticeSections(
|
||||
full_url,
|
||||
std::get<0>(splited_host_name),
|
||||
std::get<1>(splited_host_name),
|
||||
std::get<2>(splited_host_name),
|
||||
rule.getMode(),
|
||||
policy,
|
||||
@@ -1531,11 +1577,11 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, c
|
||||
|
||||
R default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
// add default rule to policy
|
||||
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
|
||||
|
||||
vector<R> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
|
||||
createPolicyElements<T, R>(specific_rules, default_rule, appsec_policy, policy_name);
|
||||
|
||||
// add default rule to policy
|
||||
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
@@ -1545,17 +1591,10 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy<V1beta2AppsecLinuxPolicy, Ne
|
||||
const string &policy_name,
|
||||
const V1beta2AppsecLinuxPolicy &appsec_policy)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name;
|
||||
dbgTrace(D_LOCAL_POLICY) << "Proccesing v1beta2 policy, name: " << policy_name;
|
||||
|
||||
NewParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
// add default rule to policy
|
||||
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
|
||||
default_rule,
|
||||
default_rule,
|
||||
appsec_policy,
|
||||
policy_name);
|
||||
|
||||
vector<NewParsedRule> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
|
||||
createPolicyElements<V1beta2AppsecLinuxPolicy, NewParsedRule>(
|
||||
specific_rules,
|
||||
@@ -1563,6 +1602,13 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy<V1beta2AppsecLinuxPolicy, Ne
|
||||
appsec_policy,
|
||||
policy_name
|
||||
);
|
||||
|
||||
// add default rule to policy
|
||||
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
|
||||
default_rule,
|
||||
default_rule,
|
||||
appsec_policy,
|
||||
policy_name);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
@@ -1572,15 +1618,31 @@ PolicyMakerUtils::proccesSingleAppsecPolicy(
|
||||
const string &policy_version,
|
||||
const string &local_appsec_policy_path)
|
||||
{
|
||||
Maybe<AppsecLinuxPolicy> maybe_policy = openFileAsJson<AppsecLinuxPolicy>(policy_path);
|
||||
if (!maybe_policy.ok()){
|
||||
dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr();
|
||||
return "";
|
||||
|
||||
Maybe<V1beta2AppsecLinuxPolicy> maybe_policy_v1beta2 = openFileAsJson<V1beta2AppsecLinuxPolicy>(policy_path);
|
||||
if (maybe_policy_v1beta2.ok()) {
|
||||
policy_version_name = "v1beta2";
|
||||
createAgentPolicyFromAppsecPolicy<V1beta2AppsecLinuxPolicy, NewParsedRule>(
|
||||
getPolicyName(policy_path),
|
||||
maybe_policy_v1beta2.unpack()
|
||||
);
|
||||
} else {
|
||||
policy_version_name = "v1beta1";
|
||||
dbgInfo(D_LOCAL_POLICY)
|
||||
<< "Failed to retrieve AppSec local policy with version: v1beta2, Trying version: v1beta1";
|
||||
|
||||
Maybe<AppsecLinuxPolicy> maybe_policy_v1beta1 = openFileAsJson<AppsecLinuxPolicy>(policy_path);
|
||||
if (!maybe_policy_v1beta1.ok()){
|
||||
dbgWarning(D_LOCAL_POLICY) << maybe_policy_v1beta1.getErr();
|
||||
return "";
|
||||
}
|
||||
createAgentPolicyFromAppsecPolicy<AppsecLinuxPolicy, ParsedRule>(
|
||||
getPolicyName(policy_path),
|
||||
maybe_policy_v1beta1.unpack()
|
||||
);
|
||||
|
||||
if (getenv("OPENAPPSEC_STANDALONE")) rpmBuildNginxServers(maybe_policy_v1beta1.unpack());
|
||||
}
|
||||
createAgentPolicyFromAppsecPolicy<AppsecLinuxPolicy, ParsedRule>(
|
||||
getPolicyName(policy_path),
|
||||
maybe_policy.unpack()
|
||||
);
|
||||
|
||||
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
|
||||
return dumpPolicyToFile(
|
||||
@@ -1588,3 +1650,114 @@ PolicyMakerUtils::proccesSingleAppsecPolicy(
|
||||
local_appsec_policy_path
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::rpmReportInfo(const std::string &msg)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << msg;
|
||||
|
||||
LogGen(
|
||||
msg,
|
||||
ReportIS::Audience::SECURITY,
|
||||
ReportIS::Severity::INFO,
|
||||
ReportIS::Priority::LOW,
|
||||
ReportIS::Tags::ORCHESTRATOR
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::rpmReportError(const std::string &msg)
|
||||
{
|
||||
dbgWarning(D_LOCAL_POLICY) << msg;
|
||||
|
||||
LogGen(
|
||||
msg,
|
||||
ReportIS::Audience::SECURITY,
|
||||
ReportIS::Severity::CRITICAL,
|
||||
ReportIS::Priority::URGENT,
|
||||
ReportIS::Tags::ORCHESTRATOR
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::rpmBuildNginxServers(const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
rpmReportInfo("Started building NGINX servers");
|
||||
|
||||
ReverseProxyBuilder::init();
|
||||
bool full_success = true;
|
||||
bool partial_success = false;
|
||||
set<pair<string, bool>> processed_rules;
|
||||
for (ParsedRule const &rule : policy.getAppsecPolicySpec().getSpecificRules()) {
|
||||
tuple<string, string, string> splited_host_name = splitHostName(rule.getHost());
|
||||
string host = std::get<0>(splited_host_name);
|
||||
if (host.empty() || rule.rpmGetUpstream().empty()) continue;
|
||||
|
||||
string location = std::get<2>(splited_host_name);
|
||||
if (location.empty()) location = "/";
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY)
|
||||
<< "Building NGINX server: "
|
||||
<< host
|
||||
<< ", location: "
|
||||
<< location
|
||||
<< " RP-Settings: "
|
||||
<< rule.rpmGetRPSettings();
|
||||
|
||||
RPMSettings rp_settings =
|
||||
rpmGetAppsecRPSettingSpec<AppsecLinuxPolicy, RPMSettings>(rule.rpmGetRPSettings(), policy);
|
||||
pair<string, bool> server = {host, rule.rpmIsHttps()};
|
||||
auto it = processed_rules.find(server);
|
||||
if (it != processed_rules.end()) {
|
||||
auto maybe_res = ReverseProxyBuilder::addNginxServerLocation(location, host, rule, rp_settings);
|
||||
if (!maybe_res.ok()) {
|
||||
rpmReportError(
|
||||
"Could not add an NGINX server location: " + location + " to server: " + host +
|
||||
", error: " + maybe_res.getErr()
|
||||
);
|
||||
full_success = false;
|
||||
continue;
|
||||
}
|
||||
rpmReportInfo("NGINX server location: " + location + " was successfully added to server: " + host);
|
||||
partial_success = true;
|
||||
} else {
|
||||
auto maybe_res = ReverseProxyBuilder::createNewNginxServer(host, rule, rp_settings);
|
||||
if (!maybe_res.ok()) {
|
||||
rpmReportError("Could not create a new NGINX server: " + host + ", error: " + maybe_res.getErr());
|
||||
full_success = false;
|
||||
continue;
|
||||
}
|
||||
rpmReportInfo(
|
||||
(rule.rpmIsHttps() ? string("SSL") : string("HTTP")) + " NGINX server: " + host +
|
||||
" was successfully built"
|
||||
);
|
||||
processed_rules.insert(server);
|
||||
|
||||
maybe_res = ReverseProxyBuilder::addNginxServerLocation(location, host, rule, rp_settings);
|
||||
if (!maybe_res.ok()) {
|
||||
rpmReportError(
|
||||
"Could not add an NGINX server location: " + location + " to server: " + host +
|
||||
", error: " + maybe_res.getErr()
|
||||
);
|
||||
full_success = false;
|
||||
continue;
|
||||
}
|
||||
rpmReportInfo("NGINX server location: " + location + " was successfully added to server: " + host);
|
||||
partial_success = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto maybe_reload_nginx = ReverseProxyBuilder::reloadNginx();
|
||||
if (!maybe_reload_nginx.ok()) {
|
||||
rpmReportError("Could not reload NGINX, error: " + maybe_reload_nginx.getErr());
|
||||
return;
|
||||
}
|
||||
|
||||
if (full_success) {
|
||||
rpmReportInfo("NGINX configuration was loaded successfully!");
|
||||
} else if (partial_success) {
|
||||
rpmReportInfo("NGINX configuration was partially loaded");
|
||||
} else {
|
||||
rpmReportError("Could not load any NGINX configuration");
|
||||
}
|
||||
}
|
||||
|
456
components/security_apps/local_policy_mgmt_gen/reverse_proxy_section.cc
Executable file
456
components/security_apps/local_policy_mgmt_gen/reverse_proxy_section.cc
Executable file
@@ -0,0 +1,456 @@
|
||||
// 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 "reverse_proxy_section.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <fstream>
|
||||
|
||||
#include "local_policy_mgmt_gen.h"
|
||||
#include "local_policy_common.h"
|
||||
#include "appsec_practice_section.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_LOCAL_POLICY);
|
||||
|
||||
static string conf_base_path = "/etc/cp/conf/";
|
||||
static string certs_path = "/etc/certs/";
|
||||
static string nginx_templates_path = "/etc/nginx/nginx-templates/";
|
||||
static const string nginx_configuration_path = "openappsec-nginx-servers/";
|
||||
static const string nginx_http_server_template = "nginx-http-server";
|
||||
static const string nginx_ssl_server_template = "nginx-ssl-server";
|
||||
static const string nginx_location_template = "nginx-location-block";
|
||||
|
||||
static const boost::regex host_template("<host>");
|
||||
static const boost::regex private_key_template("<private-key>");
|
||||
static const boost::regex certificate_template("<certificate>");
|
||||
static const boost::regex location_template("<location>");
|
||||
static const boost::regex upstream_template("<upstream>");
|
||||
static const boost::regex host_header_template("<host-header>");
|
||||
static const boost::regex dns_resolver_template("<dns-resolver>");
|
||||
|
||||
class ReverseProxyCertUtils
|
||||
{
|
||||
public:
|
||||
static std::pair<std::string, std::string> findMatchingCertificate(const std::string &host);
|
||||
static void init();
|
||||
|
||||
private:
|
||||
static std::vector<std::string> getFilesByExtension(const std::string &extension);
|
||||
static void untarCertificatesPackages();
|
||||
|
||||
static Maybe<std::string> extractModulus(const std::string &path, const std::string &type);
|
||||
|
||||
static std::unordered_map<std::string, std::string>
|
||||
calculatePublicModulus(const std::vector<std::string> &certs);
|
||||
|
||||
static std::unordered_map<std::string, std::string>
|
||||
calculatePrivateModulus(const std::vector<std::string> &keys);
|
||||
|
||||
static std::unordered_map<std::string, std::string> cert_key_map;
|
||||
};
|
||||
unordered_map<string, string> ReverseProxyCertUtils::cert_key_map;
|
||||
|
||||
void
|
||||
RPMSettings::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Loading RP Settings";
|
||||
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("host-header", host_hdr, archive_in, "$host");
|
||||
parseAppsecJSONKey<string>("dns-resolver", dns_resolver, archive_in, "127.0.0.11");
|
||||
}
|
||||
|
||||
const string &
|
||||
RPMSettings::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
string
|
||||
RPMSettings::applySettings(const std::string &server_content) const
|
||||
{
|
||||
string new_server_content = ReverseProxyBuilder::replaceTemplate(server_content, host_header_template, host_hdr);
|
||||
return ReverseProxyBuilder::replaceTemplate(new_server_content, dns_resolver_template, dns_resolver);
|
||||
}
|
||||
|
||||
void
|
||||
ReverseProxyCertUtils::init()
|
||||
{
|
||||
certs_path = getProfileAgentSettingWithDefault<string>("/etc/certs/", "openappsec.reverseProxy.certs");
|
||||
|
||||
untarCertificatesPackages();
|
||||
cert_key_map.clear();
|
||||
auto public_modulus_map = calculatePublicModulus(getFilesByExtension(".pem"));
|
||||
auto private_modulus_map = calculatePrivateModulus(getFilesByExtension(".key"));
|
||||
for (const auto &public_modulus_entry : public_modulus_map) {
|
||||
auto public_modulus = public_modulus_entry.second;
|
||||
if (private_modulus_map.find(public_modulus) != private_modulus_map.end()) {
|
||||
dbgTrace(D_LOCAL_POLICY)
|
||||
<< "Successfully parsed certificate: "
|
||||
<< public_modulus_entry.first
|
||||
<< " with private key: "
|
||||
<< private_modulus_map[public_modulus];
|
||||
|
||||
cert_key_map[public_modulus_entry.first] = private_modulus_map[public_modulus];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<string>
|
||||
ReverseProxyCertUtils::getFilesByExtension(const string &extension)
|
||||
{
|
||||
auto maybe_files = NGEN::Filesystem::getDirectoryFiles(certs_path);
|
||||
if (!maybe_files.ok()) return {};
|
||||
|
||||
auto files = maybe_files.unpack();
|
||||
files.erase(
|
||||
remove_if(
|
||||
files.begin(),
|
||||
files.end(),
|
||||
[&](const string& file) { return file.length() < 4 || file.substr(file.length() - 4) != extension; }
|
||||
),
|
||||
files.end()
|
||||
);
|
||||
|
||||
for (const auto &file : files) {
|
||||
dbgTrace(D_LOCAL_POLICY) << "Found file: " << file;
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
pair<string, string>
|
||||
ReverseProxyCertUtils::findMatchingCertificate(const string &host)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Looking for a matching certificate to host: " << host;
|
||||
|
||||
for (const auto &entry : cert_key_map) {
|
||||
string cert_path = entry.first;
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "Checking match of certificate: " << cert_path;
|
||||
|
||||
// Create a BIO object to read the certificate
|
||||
BIO* cert_bio = BIO_new_file(cert_path.c_str(), "rb");
|
||||
if (!cert_bio) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Could not open certificate file: " << cert_path;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load the PEM-encoded public key from the file
|
||||
X509 *cert = PEM_read_bio_X509(cert_bio, nullptr, nullptr, nullptr);
|
||||
if (!cert) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Could not parse X509 certificate file: " << cert_path;
|
||||
BIO_free(cert_bio);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the subject alternative name extension
|
||||
STACK_OF(GENERAL_NAME)* san_names = static_cast<STACK_OF(GENERAL_NAME)*>(
|
||||
X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr)
|
||||
);
|
||||
|
||||
if (!san_names) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "No Subject Alternative Name found in the certificate: " << cert_path;
|
||||
X509_free(cert);
|
||||
BIO_free(cert_bio);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate through the SAN entries
|
||||
for (int i = 0; i < sk_GENERAL_NAME_num(san_names); ++i) {
|
||||
GENERAL_NAME* name = sk_GENERAL_NAME_value(san_names, i);
|
||||
if (name->type == GEN_DNS) {
|
||||
const char* san = reinterpret_cast<const char*>(ASN1_STRING_get0_data(name->d.dNSName));
|
||||
|
||||
if (X509_check_host(cert, host.c_str(), host.length(), 0, nullptr) == 1) {
|
||||
dbgTrace(D_LOCAL_POLICY) << "Found matching certificate: " << cert_path << ", DNS name: " << san;
|
||||
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
||||
X509_free(cert);
|
||||
BIO_free(cert_bio);
|
||||
return {cert_path, cert_key_map[cert_path]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "Certificate: " << cert_path << " does not match host: " << host;
|
||||
|
||||
// Clean up
|
||||
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
||||
X509_free(cert);
|
||||
BIO_free(cert_bio);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<std::string>
|
||||
ReverseProxyCertUtils::extractModulus(const string &path, const string &type)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Started calculating modulus of: " << path << ", type: " << type;
|
||||
|
||||
string modulus_cmd = "openssl " + type + " -noout -modulus -in " + path + "; echo $?";
|
||||
auto modulus_maybe = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(modulus_cmd);
|
||||
if (!modulus_maybe.ok()) return genError("Could not complete command, error: " + modulus_maybe.getErr());
|
||||
|
||||
auto modulus_cmd_output = NGEN::Strings::removeTrailingWhitespaces(modulus_maybe.unpack());
|
||||
if (modulus_cmd_output.back() != '0') return genError("Could not extract modulus, error: " + modulus_cmd_output);
|
||||
|
||||
modulus_cmd_output.pop_back();
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "Extracted modulus for: " << path << ", " << modulus_cmd_output;
|
||||
|
||||
return modulus_cmd_output;
|
||||
}
|
||||
|
||||
unordered_map<string, string>
|
||||
ReverseProxyCertUtils::calculatePublicModulus(const vector<string> &certs)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Calculating certificates modulus";
|
||||
|
||||
unordered_map<string, string> certs_modulus;
|
||||
for (const string &cert_file_name : certs) {
|
||||
string cert_path = certs_path + cert_file_name;
|
||||
auto modulus = extractModulus(cert_path, "x509");
|
||||
if (!modulus.ok()) {
|
||||
dbgWarning(D_LOCAL_POLICY) << modulus.getErr();
|
||||
continue;
|
||||
}
|
||||
|
||||
certs_modulus[cert_path] = modulus.unpack();
|
||||
}
|
||||
|
||||
return certs_modulus;
|
||||
}
|
||||
|
||||
unordered_map<string, string>
|
||||
ReverseProxyCertUtils::calculatePrivateModulus(const vector<string> &keys)
|
||||
{
|
||||
unordered_map<string, string> key_modulus;
|
||||
for (const string &private_key_file_name : keys) {
|
||||
string private_key_path = certs_path + private_key_file_name;
|
||||
auto modulus = extractModulus(private_key_path, "rsa");
|
||||
if (!modulus.ok()) {
|
||||
dbgWarning(D_LOCAL_POLICY) << modulus.getErr();
|
||||
continue;
|
||||
}
|
||||
|
||||
key_modulus[modulus.unpack()] = private_key_path;
|
||||
}
|
||||
|
||||
return key_modulus;
|
||||
}
|
||||
|
||||
void
|
||||
ReverseProxyCertUtils::untarCertificatesPackages()
|
||||
{
|
||||
vector<string> cert_pkgs = getFilesByExtension(".pkg");
|
||||
if (cert_pkgs.empty()) return;
|
||||
|
||||
for (const auto &cert_pkg : cert_pkgs) {
|
||||
dbgTrace(D_LOCAL_POLICY) << "Untaring certificate package: " << cert_pkg;
|
||||
string untar_cmd = "tar -C " + certs_path + " -xvf " + certs_path + cert_pkg;
|
||||
auto maybe_tar_res = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(untar_cmd);
|
||||
if (!maybe_tar_res.ok()) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Untar package error: " << maybe_tar_res.getErr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
ReverseProxyBuilder::replaceTemplate(
|
||||
const string &content,
|
||||
const boost::regex &nginx_directive_template,
|
||||
const string &value)
|
||||
{
|
||||
return NGEN::Regex::regexReplace(__FILE__, __LINE__, content, nginx_directive_template, value);
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
ReverseProxyBuilder::getTemplateContent(const string &nginx_conf_template)
|
||||
{
|
||||
ifstream nginx_template_in(nginx_templates_path + nginx_conf_template);
|
||||
if (!nginx_template_in.is_open()) return genError("Could not open the " + nginx_conf_template + " template");
|
||||
|
||||
string file_content((istreambuf_iterator<char>(nginx_template_in)), istreambuf_iterator<char>());
|
||||
nginx_template_in.close();
|
||||
|
||||
return file_content;
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
ReverseProxyBuilder::createSSLNginxServer(const string &host, const RPMSettings &rp_settings)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Creating SSL NGINX server: " << host;
|
||||
|
||||
pair<string, string> cert_key = ReverseProxyCertUtils::findMatchingCertificate(host);
|
||||
if (cert_key.first.empty() || cert_key.second.empty()) {
|
||||
return genError("Cannot find matching certificates to host: " + host);
|
||||
}
|
||||
|
||||
auto maybe_server_content = getTemplateContent(nginx_ssl_server_template);
|
||||
if (!maybe_server_content.ok()) return maybe_server_content.passErr();
|
||||
|
||||
string server_content = replaceTemplate(maybe_server_content.unpack(), host_template, host);
|
||||
server_content = replaceTemplate(server_content, private_key_template, cert_key.second);
|
||||
server_content = replaceTemplate(server_content, certificate_template, cert_key.first);
|
||||
server_content = rp_settings.applySettings(server_content);
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "NGINX SSL Server content: " << server_content;
|
||||
|
||||
string conf_path = conf_base_path + nginx_configuration_path + "/443_" + host + ".conf";
|
||||
ofstream server_file(conf_path, ofstream::out | ofstream::trunc);
|
||||
if (!server_file.is_open()) {
|
||||
return genError("Could not open the output SSL NGINX configuration file: " + conf_path);
|
||||
}
|
||||
|
||||
server_file << server_content;
|
||||
server_file.close();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
ReverseProxyBuilder::createHTTPNginxServer(const string &host, const RPMSettings &rp_settings)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Creating HTTP NGINX server: " << host;
|
||||
|
||||
auto maybe_server_content = getTemplateContent(nginx_http_server_template);
|
||||
if (!maybe_server_content.ok()) return maybe_server_content.passErr();
|
||||
|
||||
string server_content = replaceTemplate(maybe_server_content.unpack(), host_template, host);
|
||||
server_content = rp_settings.applySettings(server_content);
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "NGINX HTTP Server content: " << server_content;
|
||||
|
||||
string http_server_conf_path = conf_base_path + nginx_configuration_path + "80_" + host + ".conf";
|
||||
ofstream server_file(http_server_conf_path, ofstream::out | ofstream::trunc);
|
||||
if (!server_file.is_open()) {
|
||||
return genError("Could not open the output HTTP NGINX configuration file: " + http_server_conf_path);
|
||||
}
|
||||
|
||||
server_file << server_content;
|
||||
server_file.close();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
ReverseProxyBuilder::addNginxServerLocation(
|
||||
string location,
|
||||
const string &host,
|
||||
const ParsedRule &rule,
|
||||
const RPMSettings &rp_settings)
|
||||
{
|
||||
string port = rule.rpmIsHttps() ? string("443") : string("80");
|
||||
string location_conf_path = conf_base_path + nginx_configuration_path + port + '_' + host + "_locations/";
|
||||
|
||||
dbgFlow(D_LOCAL_POLICY) << "Adding a new NGINX location: " << location << " to: " << location_conf_path;
|
||||
|
||||
NGEN::Filesystem::makeDirRecursive(location_conf_path);
|
||||
|
||||
if (location.empty() || location.find_first_not_of('/') == string::npos)
|
||||
{
|
||||
location = "/";
|
||||
location_conf_path += "root_location.conf";
|
||||
}
|
||||
else
|
||||
{
|
||||
string location_conf_basename = location.substr(1, location.length() - 1) + "_location";
|
||||
replace(location_conf_basename.begin(), location_conf_basename.end(), '/', '_');
|
||||
location_conf_path += location_conf_basename + ".conf";
|
||||
}
|
||||
auto maybe_location_content = getTemplateContent(nginx_location_template);
|
||||
if (!maybe_location_content.ok()) return maybe_location_content.passErr();
|
||||
|
||||
string location_content = replaceTemplate(maybe_location_content.unpack(), location_template, location);
|
||||
location_content = replaceTemplate(location_content, upstream_template, rule.rpmGetUpstream());
|
||||
location_content = rp_settings.applySettings(location_content);
|
||||
|
||||
dbgTrace(D_LOCAL_POLICY) << "NGINX server location content: " << location_content;
|
||||
|
||||
ofstream location_file(location_conf_path, ofstream::out | ofstream::trunc);
|
||||
if (!location_file.is_open()) {
|
||||
return genError("Could not open the output NGINX location block: " + location_conf_path);
|
||||
}
|
||||
|
||||
location_file << location_content;
|
||||
location_file.close();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
ReverseProxyBuilder::createNewNginxServer(const string &host, const ParsedRule &rule, const RPMSettings &rp_settings)
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Creating a new NGINX server: " << host << ", SSL: " << rule.rpmIsHttps();
|
||||
|
||||
if (rule.rpmIsHttps()) {
|
||||
auto maybe_res = ReverseProxyBuilder::createSSLNginxServer(host, rp_settings);
|
||||
if (!maybe_res.ok()) {
|
||||
return genError("Could not create an SSL NGINX server configuration: " + maybe_res.getErr());
|
||||
}
|
||||
} else {
|
||||
auto maybe_res = ReverseProxyBuilder::createHTTPNginxServer(host, rp_settings);
|
||||
if (!maybe_res.ok()) {
|
||||
return genError("Could not create an HTTP NGINX server: " + maybe_res.getErr());
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
ReverseProxyBuilder::reloadNginx()
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Reloading NGINX...";
|
||||
|
||||
auto maybe_nginx_t = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(
|
||||
"nginx -t 2>&1; echo $?"
|
||||
);
|
||||
|
||||
if (!maybe_nginx_t.ok()){
|
||||
return genError("Could not check NGINX configuration: " + maybe_nginx_t.getErr());
|
||||
}
|
||||
|
||||
string nginx_t_output = NGEN::Strings::removeTrailingWhitespaces(maybe_nginx_t.unpack());
|
||||
if (nginx_t_output.back() != '0') return genError("Invalid NGINX configuration: " + nginx_t_output);
|
||||
|
||||
auto maybe_nginx_reload = Singleton::Consume<I_ShellCmd>::by<LocalPolicyMgmtGenerator>()->getExecOutput(
|
||||
"nginx -s reload 2>&1;"
|
||||
);
|
||||
|
||||
if (!maybe_nginx_reload.ok()){
|
||||
return genError("Could not reload NGINX: " + maybe_nginx_reload.getErr());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
ReverseProxyBuilder::init()
|
||||
{
|
||||
conf_base_path = getConfigurationWithDefault<string>("/etc/cp/conf/", "Config Component", "configuration path");
|
||||
nginx_templates_path = getProfileAgentSettingWithDefault<string>(
|
||||
"/etc/nginx/nginx-templates/", "openappsec.reverseProxy.nginxTemplates"
|
||||
);
|
||||
|
||||
NGEN::Filesystem::deleteDirectory(conf_base_path + nginx_configuration_path, true);
|
||||
NGEN::Filesystem::makeDir(conf_base_path + nginx_configuration_path);
|
||||
ReverseProxyCertUtils::init();
|
||||
}
|
@@ -156,6 +156,7 @@ RulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
RulesConfigRulebase::RulesConfigRulebase(
|
||||
const string &_name,
|
||||
const string &_url,
|
||||
const string &_port,
|
||||
const string &_uri,
|
||||
vector<PracticeSection> _practices,
|
||||
vector<ParametersSection> _parameters,
|
||||
@@ -169,39 +170,19 @@ RulesConfigRulebase::RulesConfigRulebase(
|
||||
try {
|
||||
bool any = _name == "Any" && _url == "Any" && _uri == "Any";
|
||||
id = any ? "Any" : _url+_uri;
|
||||
if (_uri != "/") {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)" +
|
||||
string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)" +
|
||||
string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
")"
|
||||
")";
|
||||
} else {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)"
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)"
|
||||
")"
|
||||
")";
|
||||
if (any) {
|
||||
context ="All()";
|
||||
return;
|
||||
}
|
||||
string host_check = "Any(EqualHost(" + _url + ")),";
|
||||
string uri_check = (_uri.empty() || _uri == "/" ) ? "" : ",BeginWithUri(" + _uri + ")";
|
||||
auto ports = _port.empty() ? vector<string>({"80", "443"}) : vector<string>({_port});
|
||||
context = "Any(";
|
||||
for (auto &port : ports) {
|
||||
string check_last = (ports.size() == 1 || port == "443") ? ")" : "),";
|
||||
context += "All(" + host_check + "EqualListeningPort(" + port + ")" + uri_check + check_last;
|
||||
}
|
||||
context += ")";
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "Failed to generate rule UUID. Error: " << e.what();
|
||||
}
|
||||
@@ -284,6 +265,7 @@ UsersIdentifiersRulebase::UsersIdentifiersRulebase(
|
||||
const string &
|
||||
UsersIdentifiersRulebase::getIdentifier() const
|
||||
{
|
||||
if (source_identifiers.empty()) return source_identifier;
|
||||
return source_identifiers[0].getIdentifier();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
Reference in New Issue
Block a user