mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 11:16:30 +03:00
Support local managment for embedded agent on nginx
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __I_K8S_POLICY_GEN_H__
|
||||
#define __I_K8S_POLICY_GEN_H__
|
||||
#ifndef __I_LOCAL_POLICY_MGMT_GEN_H__
|
||||
#define __I_LOCAL_POLICY_MGMT_GEN_H__
|
||||
|
||||
class I_K8S_Policy_Gen
|
||||
{
|
||||
@@ -24,4 +24,4 @@ protected:
|
||||
~I_K8S_Policy_Gen() {}
|
||||
};
|
||||
|
||||
#endif //__I_K8S_POLICY_GEN_H__
|
||||
#endif //__I_LOCAL_POLICY_MGMT_GEN_H__
|
@@ -11,26 +11,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __K8S_POLICY_GEN_H__
|
||||
#define __K8S_POLICY_GEN_H__
|
||||
#ifndef __LOCAL_POLICY_MGMT_GEN_H__
|
||||
#define __LOCAL_POLICY_MGMT_GEN_H__
|
||||
|
||||
#include "config.h"
|
||||
#include "component.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_environment.h"
|
||||
#include "i_k8s_policy_gen.h"
|
||||
#include "i_local_policy_mgmt_gen.h"
|
||||
|
||||
class K8sPolicyGenerator
|
||||
class LocalPolicyMgmtGenerator
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_K8S_Policy_Gen>,
|
||||
Singleton::Provide<I_LocalPolicyMgmtGen>,
|
||||
Singleton::Consume<Config::I_Config>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
K8sPolicyGenerator();
|
||||
~K8sPolicyGenerator();
|
||||
LocalPolicyMgmtGenerator();
|
||||
~LocalPolicyMgmtGenerator();
|
||||
|
||||
void preload() override;
|
||||
|
||||
@@ -41,4 +41,4 @@ private:
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __K8S_POLICY_GEN_H__
|
||||
#endif // __LOCAL_POLICY_MGMT_GEN_H__
|
@@ -12,6 +12,6 @@ add_subdirectory(manifest_controller)
|
||||
add_subdirectory(update_communication)
|
||||
add_subdirectory(details_resolver)
|
||||
add_subdirectory(health_check)
|
||||
add_subdirectory(k8s_policy_gen)
|
||||
add_subdirectory(local_policy_mgmt_gen)
|
||||
|
||||
add_subdirectory(orchestration_ut)
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "singleton.h"
|
||||
#include "i_update_communication.h"
|
||||
#include "fog_authenticator.h"
|
||||
#include "i_k8s_policy_gen.h"
|
||||
#include "i_local_policy_mgmt_gen.h"
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_orchestration_status.h"
|
||||
@@ -39,7 +39,7 @@
|
||||
class HybridCommunication
|
||||
:
|
||||
public FogAuthenticator,
|
||||
Singleton::Consume<I_K8S_Policy_Gen>
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>
|
||||
{
|
||||
public:
|
||||
virtual void init() override;
|
||||
|
@@ -1 +0,0 @@
|
||||
add_library(k8s_policy_gen k8s_policy_gen.cc)
|
@@ -0,0 +1 @@
|
||||
add_library(local_policy_mgmt_gen local_policy_mgmt_gen.cc)
|
@@ -24,6 +24,7 @@
|
||||
#include "customized_cereal_map.h"
|
||||
#include "k8s_policy_common.h"
|
||||
#include "triggers_section.h"
|
||||
#include "exceptions_section.h"
|
||||
#include "trusted_sources_section.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
@@ -316,18 +317,21 @@ public:
|
||||
parseAppsecJSONKey<AppSecPracticeSnortSignatures>("snort-signatures", snort_signatures, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeWebAttacks>("web-attacks", web_attacks, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeAntiBot>("anti-bot", anti_bot, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", practice_name, archive_in);
|
||||
}
|
||||
|
||||
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const { return openapi_schema_validation; }
|
||||
const AppSecPracticeSnortSignatures & getSnortSignatures() const { return snort_signatures; }
|
||||
const AppSecPracticeWebAttacks & getWebAttacks() const { return web_attacks; }
|
||||
const AppSecPracticeAntiBot & getAntiBot() const { return anti_bot; }
|
||||
const std::string & getName() const { return practice_name; }
|
||||
|
||||
private:
|
||||
AppSecPracticeOpenSchemaAPI openapi_schema_validation;
|
||||
AppSecPracticeSnortSignatures snort_signatures;
|
||||
AppSecPracticeWebAttacks web_attacks;
|
||||
AppSecPracticeAntiBot anti_bot;
|
||||
std::string practice_name;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
@@ -753,6 +757,54 @@ private:
|
||||
std::vector<ParsedRule> specific_rules;
|
||||
};
|
||||
|
||||
class AppsecLinuxPolicy : Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
|
||||
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppSecPracticeSpec>>("practices", practices, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppsecTriggerSpec>>("logtriggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppSecCustomResponseSpec>>("customresponses", custom_responses, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<std::vector<TrustedSourcesSpec>>("trustedsources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<std::vector<SourceIdentifierSpecWrapper>>(
|
||||
"sourceidentifiers",
|
||||
sources_identifier,
|
||||
archive_in
|
||||
);
|
||||
}
|
||||
|
||||
const AppsecPolicySpec & getAppsecPolicySpec() const { return policies; }
|
||||
|
||||
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const { return practices; }
|
||||
|
||||
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const { return log_triggers; }
|
||||
|
||||
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const { return custom_responses; }
|
||||
|
||||
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const { return exceptions; }
|
||||
|
||||
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const { return trusted_sources; }
|
||||
|
||||
const std::vector<SourceIdentifierSpecWrapper> &
|
||||
getAppsecSourceIdentifierSpecs() const
|
||||
{
|
||||
return sources_identifier;
|
||||
}
|
||||
|
||||
private:
|
||||
AppsecPolicySpec policies;
|
||||
std::vector<AppSecPracticeSpec> practices;
|
||||
std::vector<AppsecTriggerSpec> log_triggers;
|
||||
std::vector<AppSecCustomResponseSpec> custom_responses;
|
||||
std::vector<AppsecExceptionSpec> exceptions;
|
||||
std::vector<TrustedSourcesSpec> trusted_sources;
|
||||
std::vector<SourceIdentifierSpecWrapper> sources_identifier;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecPolicySpec &obj)
|
||||
{
|
@@ -77,6 +77,9 @@ template <typename T>
|
||||
class AppsecSpecParser : public ClientRest
|
||||
{
|
||||
public:
|
||||
AppsecSpecParser() = default;
|
||||
AppsecSpecParser(const T &_spec) : spec(_spec) {}
|
||||
|
||||
bool
|
||||
loadJson(const std::string &json)
|
||||
{
|
@@ -200,7 +200,7 @@ private:
|
||||
int response_code;
|
||||
};
|
||||
|
||||
class AppSecWebUserResponseSpec
|
||||
class AppSecCustomResponseSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
@@ -209,6 +209,8 @@ public:
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec";
|
||||
parseAppsecJSONKey<int>("http-response-code", httpResponseCode, archive_in, 403);
|
||||
parseAppsecJSONKey<std::string>("mode", mode, archive_in, "block-page");
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
|
||||
if (mode == "block-page") {
|
||||
parseAppsecJSONKey<std::string>(
|
||||
"message-body",
|
||||
@@ -229,16 +231,18 @@ public:
|
||||
const std::string & getMessageBody() const { return messageBody; }
|
||||
const std::string & getMessageTitle() const { return messageTitle; }
|
||||
const std::string & getMode() const { return mode; }
|
||||
const std::string & getName() const { return name; }
|
||||
|
||||
private:
|
||||
int httpResponseCode;
|
||||
std::string messageBody;
|
||||
std::string messageTitle;
|
||||
std::string mode;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecWebUserResponseSpec &obj)
|
||||
operator<<(std::ostream &os, const AppSecCustomResponseSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "mode: "
|
||||
@@ -467,7 +471,7 @@ public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgError(D_K8S_POLICY) << "AppsecTriggerLogDestination load";
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
|
||||
@@ -547,6 +551,7 @@ public:
|
||||
parseAppsecJSONKey<AppsecTriggerLogging>("appsec-logging", appsec_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerExtendedLogging>("extended-logging", extended_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerLogDestination>("log-destination", log_destination, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
const AppsecTriggerAccessControlLogging &
|
||||
@@ -555,6 +560,12 @@ public:
|
||||
return access_control_logging;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const AppsecTriggerAdditionalSuspiciousEventsLogging &
|
||||
getAppsecTriggerAdditionalSuspiciousEventsLogging() const
|
||||
{
|
||||
@@ -585,6 +596,7 @@ private:
|
||||
AppsecTriggerLogging appsec_logging;
|
||||
AppsecTriggerExtendedLogging extended_logging;
|
||||
AppsecTriggerLogDestination log_destination;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream &
|
@@ -35,6 +35,7 @@ public:
|
||||
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
|
||||
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("sourcesIdentifiers", sources_identifiers, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -49,8 +50,15 @@ public:
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
private:
|
||||
int min_num_of_sources;
|
||||
std::string name;
|
||||
std::vector<std::string> sources_identifiers;
|
||||
};
|
||||
|
||||
@@ -123,6 +131,34 @@ private:
|
||||
std::vector<std::string> value;
|
||||
};
|
||||
|
||||
class SourceIdentifierSpecWrapper
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper";
|
||||
parseAppsecJSONKey<std::vector<SourceIdentifierSpec>>("identifiers", identifiers, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::vector<SourceIdentifierSpec> &
|
||||
getIdentifiers() const
|
||||
{
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<SourceIdentifierSpec> identifiers;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const SourceIdentifierSpec &obj)
|
||||
{
|
@@ -363,8 +363,17 @@ public:
|
||||
default_rule.getTrustedSources() :
|
||||
parsed_rule.getTrustedSources();
|
||||
|
||||
string url = asset_name.substr(0, asset_name.find("/"));
|
||||
string uri = asset_name.substr(asset_name.find("/"));
|
||||
auto pos = asset_name.find("/");
|
||||
string url;
|
||||
string uri;
|
||||
if (pos != string::npos) {
|
||||
url = asset_name.substr(0, asset_name.find("/"));
|
||||
uri = asset_name.substr(asset_name.find("/"));
|
||||
} else {
|
||||
url = asset_name;
|
||||
uri = "";
|
||||
}
|
||||
|
||||
if (specific_assets_from_ingress.find({url, uri}) != specific_assets_from_ingress.end()) {
|
||||
// Erasing the current asset from the specific assets, because it won't have default policy
|
||||
specific_assets_from_ingress.erase({url, uri});
|
||||
@@ -435,7 +444,7 @@ public:
|
||||
}
|
||||
practice_map.emplace(practice_annotation_name, appsec_practice.getSpec());
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Successfully retrieved AppSec practice"
|
||||
<< "Successfully retrieved AppSec practice "
|
||||
<< practice_annotation_name
|
||||
<< appsec_practice.getSpec();
|
||||
}
|
||||
@@ -450,6 +459,12 @@ public:
|
||||
if (exception_map.count(exception_annotation_name) > 0) {
|
||||
exception_id = exception_map.at(exception_annotation_name).getBehaviorId();
|
||||
}
|
||||
if (asset_name == "*") {
|
||||
asset_name = "Any";
|
||||
url = "Any";
|
||||
uri = "Any";
|
||||
}
|
||||
|
||||
RulesConfigRulebase rules_config = createMultiRulesSections(
|
||||
url,
|
||||
uri,
|
@@ -45,17 +45,17 @@ HybridCommunication::init()
|
||||
string
|
||||
HybridCommunication::getChecksum(const string &policy_version)
|
||||
{
|
||||
dbgFlow(D_ORCHESTRATOR) << "Checking the policy Checksum";
|
||||
string clean_plicy_version = policy_version;
|
||||
if (!clean_plicy_version.empty() && clean_plicy_version[clean_plicy_version.size() - 1] == '\n')
|
||||
clean_plicy_version.erase(clean_plicy_version.size() - 1);
|
||||
if (!clean_plicy_version.empty() && clean_plicy_version[clean_plicy_version.size() - 1] == '\n') {
|
||||
clean_plicy_version.erase(clean_plicy_version.size() - 1);
|
||||
}
|
||||
|
||||
curr_policy = Singleton::Consume<I_K8S_Policy_Gen>::by<HybridCommunication>()->parsePolicy(clean_plicy_version);
|
||||
curr_policy = Singleton::Consume<I_LocalPolicyMgmtGen>::by<HybridCommunication>()->parsePolicy(clean_plicy_version);
|
||||
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<FogAuthenticator>();
|
||||
Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
|
||||
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
|
||||
Singleton::Consume<I_K8S_Policy_Gen>::by<HybridCommunication>()->getPolicyPath()
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>::by<HybridCommunication>()->getPolicyPath()
|
||||
);
|
||||
|
||||
if (!file_checksum.ok()) {
|
||||
@@ -69,16 +69,59 @@ Maybe<string>
|
||||
HybridCommunication::getNewVersion()
|
||||
{
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<FogAuthenticator>();
|
||||
return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger");
|
||||
auto env = Singleton::Consume<I_LocalPolicyMgmtGen>::by<HybridCommunication>()->getEnvType();
|
||||
if (env == I_LocalPolicyMgmtGen::LocalPolicyEnv::K8S) {
|
||||
return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger");
|
||||
}
|
||||
|
||||
string policy_path = getConfigurationFlagWithDefault(
|
||||
getFilesystemPathConfig() + "/conf/local_policy.yaml",
|
||||
"local_mgmt_policy"
|
||||
);
|
||||
|
||||
Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
|
||||
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
|
||||
policy_path
|
||||
);
|
||||
|
||||
if (!file_checksum.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Policy checksum was not calculated: " << file_checksum.getErr();
|
||||
return genError(file_checksum.getErr());
|
||||
}
|
||||
|
||||
return file_checksum.unpack();
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
{
|
||||
dbgFlow(D_ORCHESTRATOR) << "Getting policy update in an Hybrid Communication";
|
||||
string manifest_checksum = "";
|
||||
dbgTrace(D_ORCHESTRATOR) << "Getting updates in Hybrid Communication";
|
||||
if (access_token.ok()) {
|
||||
static const string check_update_str = "/api/v2/agents/resources";
|
||||
auto request_status = Singleton::Consume<I_Messaging>::by<HybridCommunication>()->sendObject(
|
||||
request,
|
||||
HTTPMethod::POST,
|
||||
fog_address_ex + check_update_str,
|
||||
buildOAuth2Header((*access_token).getToken())
|
||||
);
|
||||
|
||||
if (!request_status) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get response after check update request.";
|
||||
return genError("Failed to request updates");
|
||||
}
|
||||
|
||||
Maybe<string> maybe_new_manifest = request.getManifest();
|
||||
manifest_checksum = maybe_new_manifest.ok() ? maybe_new_manifest.unpack() : "";
|
||||
} else {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Acccess Token not available.";
|
||||
}
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "Getting policy update in Hybrid Communication";
|
||||
|
||||
auto maybe_new_version = getNewVersion();
|
||||
if (!maybe_new_version.ok() || maybe_new_version == curr_version) {
|
||||
request = CheckUpdateRequest("", "", "", "", "", "");
|
||||
request = CheckUpdateRequest(manifest_checksum, "", "", "", "", "");
|
||||
dbgDebug(D_ORCHESTRATOR) << "No new version is currently available";
|
||||
return Maybe<void>();
|
||||
}
|
||||
@@ -98,7 +141,7 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
<< " policy: "
|
||||
<< (policy_response.empty() ? "has no change," : "has new update," );
|
||||
|
||||
request = CheckUpdateRequest("", policy_response, "", "", "", "");
|
||||
request = CheckUpdateRequest(manifest_checksum, policy_response, "", "", "", "");
|
||||
curr_version = *maybe_new_version;
|
||||
|
||||
return Maybe<void>();
|
||||
@@ -107,13 +150,35 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
Maybe<string>
|
||||
HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
|
||||
{
|
||||
auto file_name = resourse_file.getFileName();
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Downloading attribute file on hybrid mode, file name: "
|
||||
<< resourse_file.getFileName();
|
||||
|
||||
if (resourse_file.getFileName() == "policy") {
|
||||
return curr_policy;
|
||||
}
|
||||
|
||||
|
||||
if (file_name.compare("policy") == 0) {
|
||||
return curr_policy;
|
||||
}
|
||||
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed downloading the attribute files";
|
||||
if (resourse_file.getFileName() == "manifest") {
|
||||
if (!access_token.ok()) return genError("Acccess Token not available.");
|
||||
|
||||
auto unpacked_access_token = access_token.unpack().getToken();
|
||||
|
||||
static const string file_attribute_str = "/api/v2/agents/resources/";
|
||||
Maybe<string> attribute_file = Singleton::Consume<I_Messaging>::by<HybridCommunication>()->downloadFile(
|
||||
resourse_file,
|
||||
resourse_file.getRequestMethod(),
|
||||
fog_address_ex + file_attribute_str + resourse_file.getFileName(),
|
||||
buildOAuth2Header((*access_token).getToken()) // Header
|
||||
);
|
||||
return attribute_file;
|
||||
}
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "Unnecessary attribute files downloading on hybrid mode";
|
||||
return string("");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user