Support local managment for embedded agent on nginx

This commit is contained in:
davidga
2022-11-13 13:29:35 +02:00
parent 8b01396eca
commit 1b4b7d17e0
406 changed files with 37980 additions and 35 deletions

View File

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

View File

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

View File

@@ -1 +0,0 @@
add_library(k8s_policy_gen k8s_policy_gen.cc)

View File

@@ -0,0 +1 @@
add_library(local_policy_mgmt_gen local_policy_mgmt_gen.cc)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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("");
}