Compare commits

...

7 Commits

Author SHA1 Message Date
Ned Wright
2a7ddf0666 Mar 2nd 2023 update 2023-03-02 17:08:49 +00:00
WrightNed
fef95b12b3 Merge pull request #15 from openappsec/Feb_22_2023-Dev
Feb 22nd 2023 update
2023-02-24 14:26:51 +02:00
Ned Wright
38e6e1bbcf Feb 22nd 2023 update 2023-02-22 17:20:21 +00:00
WrightNed
fd6239f44a Adding indication that policy was applied. 2023-02-22 16:36:19 +02:00
WrightNed
408ac667de Update CMakeLists.txt
Fix Typo.
2023-02-20 10:39:20 +02:00
WrightNed
2072eba07a Update CMakeLists.txt
Excluding separate installation of GraphQL library.
2023-02-20 10:33:03 +02:00
WrightNed
1f24c12a34 Merge pull request #14 from openappsec/Feb_15_2023-Dev
Feb 15 2023 dev
2023-02-19 21:30:00 +02:00
27 changed files with 411 additions and 86 deletions

View File

@@ -266,6 +266,10 @@ public:
setActiveTenantAndProfile()
{
string container_id = inst_awareness->getFamilyID().unpack();
if (container_id.empty()) {
dbgWarning(D_NGINX_ATTACHMENT) << "Failed getting a family ID";
return false;
}
dbgTrace(D_NGINX_ATTACHMENT) << "Found a family ID: " << container_id;
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<NginxAttachment>();
@@ -273,59 +277,45 @@ public:
string cmd =
"docker inspect --format='{{.Name}}' " + container_id +
" | awk -F'cp_nginx_gaia' '{print substr($2, index($2, \" \"))}'";
auto maybe_tenant_id = shell_cmd->getExecOutput(cmd, 1000, false);
auto maybe_tenant_profile_ids = shell_cmd->getExecOutput(cmd, 1000, false);
dbgTrace(D_NGINX_ATTACHMENT) << "Checking for tenant and profile IDs with the command: " << cmd;
if (maybe_tenant_id.ok()) {
string tenant_id = *maybe_tenant_id;
tenant_id.erase(remove(tenant_id.begin(), tenant_id.end(), '\n'), tenant_id.end());
dbgTrace(D_NGINX_ATTACHMENT) << "The tenant ID found is :" << tenant_id;
static string region;
if (region.empty()) {
const char *env_region = getenv("CP_NSAAS_REGION");
if (env_region) {
region = env_region;
} else {
region = getProfileAgentSettingWithDefault<string>("eu-west-1", "accessControl.region");
}
dbgInfo(D_NGINX_ATTACHMENT) << "Resolved region is " << region;
}
string profile_id = Singleton::Consume<I_TenantManager>::by<NginxAttachment>()->getProfileId(
tenant_id,
region
);
if (!profile_id.empty()) {
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
dbgTrace(D_NGINX_ATTACHMENT)
<< "NGINX attachment setting active context. Tenant ID: "
<< tenant_id
<< ", Profile ID: "
<< profile_id
<< ", Region: "
<< region;
return true;
} else {
dbgWarning(D_NGINX_ATTACHMENT)
<< "Received an empty profile ID. Tenant ID: "
<< tenant_id
<< ", Region: "
<< region;
return false;
}
} else {
if (!maybe_tenant_profile_ids.ok()) {
dbgWarning(D_NGINX_ATTACHMENT)
<< "Failed getting the tenant ID: "
<< "Failed getting the tenant and progile IDs: "
<< cmd
<< ". Error :"
<< maybe_tenant_id.getErr();
<< maybe_tenant_profile_ids.getErr();
return false;
}
dbgWarning(D_NGINX_ATTACHMENT)
<< "Parsing the tenant and profile IDs from the container name: "
<< maybe_tenant_profile_ids.unpack();
string tenant_profile_ids = maybe_tenant_profile_ids.unpack();
tenant_profile_ids.erase(
remove(tenant_profile_ids.begin(), tenant_profile_ids.end(), '\n'), tenant_profile_ids.end()
);
size_t delimeter_pos = tenant_profile_ids.find("_");
if (delimeter_pos == string::npos) {
dbgWarning(D_NGINX_ATTACHMENT)
<< "Couldn't parse tenant and profile IDs from the container name: "
<< tenant_profile_ids;
return false;
}
string tenant_id = tenant_profile_ids.substr(0, delimeter_pos);
string profile_id = tenant_profile_ids.substr(delimeter_pos + 1);
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
dbgTrace(D_NGINX_ATTACHMENT)
<< "NGINX attachment setting active context. Tenant ID: "
<< tenant_id
<< ", Profile ID: "
<< profile_id;
return true;
}

View File

@@ -50,7 +50,7 @@ checkIDP(shared_ptr<istream> file_stream)
if (line.find("<identity_portal/>") != string::npos) {
return string("false");
}
if (line.find("identity_provider") != string::npos) {
if (line.find("<central_idp ") != string::npos) {
return string("true");
}
}

View File

@@ -46,12 +46,7 @@ SHELL_CMD_HANDLER(
getSmbObjectName
)
#endif//smb
#endif // SHELL_CMD_HANDLER
// use SHELL_CMD_OUTPUT(key as string, shell command as string) to return a shell command output as the value
// for a given key
#ifdef SHELL_CMD_OUTPUT
SHELL_CMD_OUTPUT("kernel_version", "uname -r")
SHELL_CMD_OUTPUT("helloWorld", "cat /tmp/agentHelloWorld 2>/dev/null")
#endif // SHELL_CMD_OUTPUT

View File

@@ -397,7 +397,7 @@ ManifestController::Impl::handlePackage(
if (!package.isInstallable().ok()) {
string report_msg =
"Skipping installation of " + package.getName() + ". Reason: " + package.isInstallable().getErr();
"Skipping installation of package: " + package.getName() + ". Reason: " + package.isInstallable().getErr();
dbgWarning(D_ORCHESTRATOR) << report_msg;
LogGen(report_msg, Audience::SECURITY, Severity::CRITICAL, Priority::HIGH, Tags::ORCHESTRATOR);
current_packages.insert(make_pair(package.getName(), package));

View File

@@ -124,7 +124,10 @@ private:
map<string, HealthCheckStatus> field_types_status;
};
class setAgentUninstall : public ServerRest
class SetAgentUninstall
:
public ServerRest,
Singleton::Consume<I_AgentDetails>
{
public:
void
@@ -132,11 +135,13 @@ public:
{
dbgTrace(D_ORCHESTRATOR) << "Send 'agent uninstall process started' log to fog";
setConfiguration(false, "Logging", "Enable bulk of logs");
string profile_id = Singleton::Consume<I_AgentDetails>::by<SetAgentUninstall>()->getProfileId();
LogGen log (
"Agent started uninstall process",
Audience::INTERNAL,
Severity::INFO,
Priority::URGENT,
LogField("profileId", profile_id),
LogField("issuingEngine", "agentUninstallProvider"),
Tags::ORCHESTRATOR
);
@@ -167,7 +172,7 @@ public:
auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>();
rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status");
rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy");
rest->addRestCall<setAgentUninstall>(RestAction::SET, "agent-uninstall");
rest->addRestCall<SetAgentUninstall>(RestAction::SET, "agent-uninstall");
// Main loop of the Orchestration.
Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
@@ -1337,6 +1342,18 @@ private:
<< LogField("agentType", "Orchestration")
<< LogField("agentVersion", Version::get());
auto email = getSettingWithDefault<string>("", "email-address");
if (email != "") {
dbgInfo(D_ORCHESTRATOR) << "Sending registration data";
LogGen(
"Local Agent Data",
Audience::INTERNAL,
Severity::INFO,
Priority::LOW,
Tags::ORCHESTRATOR
) << LogField("userDefinedId", email);
}
reportAgentDetailsMetaData();
if (!Singleton::Consume<I_ManifestController>::by<OrchestrationComp>()->loadAfterSelfUpdate()) {
@@ -1678,5 +1695,7 @@ OrchestrationComp::preload()
registerExpectedSetting<vector<string>>("orchestration", "Orchestration status ignored policies");
registerExpectedSetting<string>("agentType");
registerExpectedSetting<string>("upgradeMode");
registerExpectedSetting<string>("email-address");
registerExpectedConfigFile("orchestration", Config::ConfigFileType::Policy);
registerExpectedConfigFile("registration-data", Config::ConfigFileType::Policy);
}

View File

@@ -312,7 +312,7 @@ TEST_F(OrchestrationTest, testAgentUninstallRest)
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "proxy", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler)));
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler)));
init();
@@ -456,6 +456,25 @@ TEST_F(OrchestrationTest, register_config)
env.fini();
}
TEST_F(OrchestrationTest, registertion_data_config)
{
EXPECT_CALL(rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _))
.WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::declareVariable)));
preload();
env.init();
string config_json =
"{\n"
" \"email-address\": \"fake@example.com\"\n"
"}";
istringstream ss(config_json);
Singleton::Consume<Config::I_Config>::from(config_comp)->loadConfiguration(ss);
EXPECT_THAT(getSetting<string>("email-address"), IsValue("fake@example.com"));
env.fini();
}
TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
{
waitForRestCall();

View File

@@ -102,6 +102,8 @@ static const boost::regex utf_evasion_for_dot_regex(utf_evasion_for_dot_helper);
static const std::string sqli_comma_evasion_regex_helper = "\"\\s*,\\s*\"";
static const boost::regex sqli_comma_evasion_regex(sqli_comma_evasion_regex_helper);
static const boost::regex space_evasion_regex("[[:space:]]{2,}");
WaapAssetState::WaapAssetState(const std::shared_ptr<WaapAssetState>& pWaapAssetState,
const std::string& waapDataFileName,
const std::string& id) :
@@ -267,6 +269,76 @@ WaapAssetState::WaapAssetState(std::shared_ptr<Signatures> signatures,
}
#endif
void trimSpaces(std::string & text) {
size_t result_position = 0;
size_t position = 0;
space_stage state = NO_SPACES;
uint32_t code;
if (text.empty()) {
return;
}
boost::cmatch what;
if (!boost::regex_search(text.c_str(), what, space_evasion_regex))
return;
dbgTrace(D_WAAP) << "Boost regex passed";
for (;position < text.size(); position++) {
code = text[position];
switch (code) {
case '\t':
case ' ':
case '\f':
case '\v':
if (state == NO_SPACES) {
state = SPACE_SYNBOL;
text[result_position++] = code;
}
break;
case '\r':
switch (state) {
case (SPACE_SYNBOL):
text[result_position - 1] = code;
state = BR_SYMBOL;
break;
case (NO_SPACES):
text[result_position++] = code;
state = BR_SYMBOL;
break;
case (BN_SYMBOL):
text[result_position++] = code;
state = BNR_SEQUENCE;
break;
default:
break;
}
break;
case '\n':
switch (state) {
case (SPACE_SYNBOL):
text[result_position - 1] = code;
state = BN_SYMBOL;
break;
case (NO_SPACES):
text[result_position++] = code;
state = BN_SYMBOL;
break;
case (BR_SYMBOL):
text[result_position++] = code;
state = BRN_SEQUENCE;
break;
default:
break;
}
break;
default:
text[result_position++] = code;
state = NO_SPACES;
}
}
text.erase(result_position, position - result_position);
}
// Python equivalent: text = re.sub(r'[^\x00-\x7F]+',' ', text)
void replaceUnicodeSequence(std::string & text, const char repl) {
std::string::iterator it = text.begin();
@@ -432,6 +504,8 @@ WaapAssetState::WaapAssetState(std::shared_ptr<Signatures> signatures,
dbgTrace(D_WAAP_SAMPLE_PREPROCESS) << "unescape: (11) '" << text << "'";
trimSpaces(text);
// 12. finally, apply tolower() to all characters of a string
// std::for_each(text.begin(), text.end(), [](char &c) { c = tolower(c); });
for (std::string::iterator pC = text.begin(); pC != text.end(); ++pC) {
@@ -726,7 +800,7 @@ checkBinaryData(const std::string &line, bool binaryDataFound)
for (size_t i=0; i<line.size(); ++i) {
unsigned char ch = (unsigned char)(line[i]);
if (!isprint(ch)) {
if (!isprint(ch) && (ch != '\r') && (ch != '\t') && (ch != '\n')) {
nonPrintableCharsCount++;
}
}
@@ -735,7 +809,7 @@ checkBinaryData(const std::string &line, bool binaryDataFound)
nonPrintableCharsCount << ", len=" << line.size();
// note: the threshold here is the same as used in base64 decoding (in function b64DecodeChunk)
if (nonPrintableCharsCount * 3 >= line.size()) {
if (nonPrintableCharsCount * 32 >= line.size()*10) {
dbgTrace(D_WAAP_SAMPLE_SCAN) << "checkBinaryData('" << line << "'): detected BINARY DATA";
binaryDataFound = true;
}

View File

@@ -34,6 +34,8 @@
#include "ScanResult.h"
#include "WaapSampleValue.h"
enum space_stage {SPACE_SYNBOL, BR_SYMBOL, BN_SYMBOL, BRN_SEQUENCE, BNR_SEQUENCE, NO_SPACES};
class IWaf2Transaction;
class WaapAssetState : public boost::noncopyable, public I_WaapAssetState
@@ -155,6 +157,7 @@ inline std::size_t hash_value(WaapAssetState::CacheKey const &cacheKey)
}
void filterUnicode(std::string & text);
void trimSpaces(std::string & text);
void replaceUnicodeSequence(std::string & text, const char repl);
std::string unescape(const std::string & s);

View File

@@ -51,6 +51,7 @@ public:
if (m_tag == "sourceip" || m_tag == "sourceidentifier") {
m_isCidr = Waap::Util::isCIDR(m_value, m_cidr);
}
m_isOverrideResponse = (m_tag == "responsebody" || m_tag == "responseBody");
if (!m_isCidr) {
// regex build may throw boost::regex_error
@@ -71,11 +72,13 @@ public:
ar(cereal::make_nvp("operand1", *m_operand1));
m_operand2 = std::make_shared<Match>();
ar(cereal::make_nvp("operand2", *m_operand2));
m_isOverrideResponse = m_operand1->m_isOverrideResponse || m_operand2->m_isOverrideResponse;
}
else if (m_op == "not") {
// If op is "NOT" get one operand
m_operand1 = std::make_shared<Match>();
ar(cereal::make_nvp("operand1", *m_operand1));
m_isOverrideResponse = m_operand1->m_isOverrideResponse;
}
}
}
@@ -113,6 +116,10 @@ public:
return false;
}
bool isOverrideResponse() const {
return m_isOverrideResponse;
}
private:
std::string m_op;
std::shared_ptr<Match> m_operand1;
@@ -122,6 +129,7 @@ private:
std::shared_ptr<boost::regex> m_valueRegex;
Waap::Util::CIDRData m_cidr;
bool m_isCidr;
bool m_isOverrideResponse;
};
class Behavior
@@ -233,6 +241,9 @@ public:
bool isChangingRequestData() const {
return m_isChangingRequestData;
}
bool isOverrideResponse() const {
return m_match.isOverrideResponse();
}
const std::string &getId() const {
return m_id;
@@ -251,6 +262,7 @@ public:
Policy(_A &ar) {
std::vector<Waap::Override::Rule> rules;
ar(cereal::make_nvp("overrides", rules));
m_isOverrideResponse = false;
for (std::vector<Waap::Override::Rule>::const_iterator it = rules.begin(); it != rules.end(); ++it) {
const Waap::Override::Rule& rule = *it;
@@ -262,6 +274,7 @@ public:
{
m_ResponseOverrides.push_back(rule);
}
m_isOverrideResponse |= rule.isOverrideResponse();
}
}
@@ -282,9 +295,14 @@ public:
dbgTrace(D_WAAP_OVERRIDE) << "Finished matching override rules.";
}
bool isOverrideResponse() const {
return m_isOverrideResponse;
}
private:
std::vector<Waap::Override::Rule> m_RequestOverrides; //overrides that change request data
std::vector<Waap::Override::Rule> m_ResponseOverrides; //overrides that change response/log data
bool m_isOverrideResponse;
};
struct State {

View File

@@ -99,6 +99,16 @@ bool WaapOverrideFunctor::operator()(const std::string& tag, const boost::regex&
else if (tag == "paramlocation" || tag == "paramLocation") {
return NGEN::Regex::regexMatch(__FILE__, __LINE__, waf2Transaction.getLocation().c_str(), what, rx);
}
else if (tag == "responsebody" || tag == "responseBody") {
waf2Transaction.getResponseInspectReasons().setApplyOverride(true);
if (!waf2Transaction.getResponseBody().empty()) {
boost::smatch matcher;
return NGEN::Regex::regexSearch(__FILE__, __LINE__,
waf2Transaction.getResponseBody().c_str(), matcher, rx);
} else {
return false;
}
}
}
catch (std::runtime_error & e) {
dbgDebug(D_WAAP_OVERRIDE) << "RegEx match for tag " << tag << " failed due to: " << e.what();

View File

@@ -24,7 +24,8 @@ openRedirect(false),
errorDisclosure(false),
errorLimiter(false),
rateLimiting(false),
collectResponseForLog(false)
collectResponseForLog(false),
applyOverride(false)
{
}
@@ -36,8 +37,9 @@ ResponseInspectReasons::shouldInspect() const
" ErrorDisclosure=" << errorDisclosure <<
" RateLimiting=" << rateLimiting <<
" ErrorLimiter=" << errorLimiter <<
" collectResponseForLog=" << collectResponseForLog;
return openRedirect || errorDisclosure || rateLimiting || errorLimiter || collectResponseForLog;
" collectResponseForLog=" << collectResponseForLog <<
" applyOverride=" << applyOverride;
return openRedirect || errorDisclosure || rateLimiting || errorLimiter || collectResponseForLog || applyOverride;
}
void
@@ -76,4 +78,18 @@ ResponseInspectReasons::setCollectResponseForLog(bool flag)
collectResponseForLog = flag;
}
void
ResponseInspectReasons::setApplyOverride(bool flag)
{
dbgTrace(D_WAAP) << "Change ResponseInspectReasons(setApplyOverride) " << applyOverride << " to " <<
flag;
applyOverride = flag;
}
bool
ResponseInspectReasons::getApplyOverride(void)
{
return applyOverride;
}
}

View File

@@ -24,12 +24,15 @@ public:
void setRateLimiting(bool flag);
void setErrorLimiter(bool flag);
void setCollectResponseForLog(bool flag);
void setApplyOverride(bool flag);
bool getApplyOverride(void);
private:
bool openRedirect;
bool errorDisclosure;
bool errorLimiter;
bool rateLimiting;
bool collectResponseForLog;
bool applyOverride;
};
}

View File

@@ -2097,6 +2097,29 @@ bool Waf2Transaction::decideResponse()
return false; // block
}
if (m_responseInspectReasons.getApplyOverride()) {
WaapConfigApplication ngenSiteConfig;
dbgTrace(D_WAAP_OVERRIDE) << "Checking exceptions for response";
if (WaapConfigApplication::getWaapSiteConfig(ngenSiteConfig)) {
dbgTrace(D_WAAP)
<< "Waf2Transaction::decideResponse(): got relevant Application configuration from the I/S";
m_overrideState = getOverrideState(&ngenSiteConfig);
// Apply overrides
if (m_overrideState.bForceBlock) {
dbgTrace(D_WAAP)
<< "Waf2Transaction::decideResponse(): setting shouldBlock to true due to override";
return false; // BLOCK
}
else if (m_overrideState.bForceException) {
dbgTrace(D_WAAP)
<< "Waf2Transaction::decideResponse(): setting shouldBlock to false due to override";
return true; // PASS
}
}
}
if (m_siteConfig) {
const std::shared_ptr<Waap::Trigger::Policy> triggerPolicy = m_siteConfig->get_TriggerPolicy();
if (!triggerPolicy) {

View File

@@ -219,6 +219,8 @@ public:
Waap::OpenRedirect::State &getOpenRedirectState() { return m_openRedirectState; }
IWaapConfig* getSiteConfig() { return m_siteConfig; }
void addNote(const std::string &note) { m_notes.push_back(note); }
const std::string &getResponseBody(void) const { return m_response_body; }
Waap::ResponseInspectReasons &getResponseInspectReasons(void) { return m_responseInspectReasons; }
private:
int finalizeDecision(IWaapConfig *sitePolicy, bool shouldBlock);

View File

@@ -556,6 +556,7 @@ Waap::Override::State Waf2Transaction::getOverrideState(IWaapConfig* sitePolicy)
Waap::Override::State overrideState;
std::shared_ptr<Waap::Override::Policy> overridePolicy = sitePolicy->get_OverridePolicy();
if (overridePolicy) { // at first we will run request overrides (in order to set the source)
m_responseInspectReasons.setApplyOverride(overridePolicy->isOverrideResponse());
overrideState.applyOverride(*overridePolicy, WaapOverrideFunctor(*this), m_matchedOverrideIds, true);
}

View File

@@ -971,6 +971,7 @@ bool decodeBase64Chunk(
int acc_bits = 0; // how many bits are filled in acc
int terminatorCharsSeen = 0; // whether '=' character was seen, and how many of them.
uint32_t nonPrintableCharsCount = 0;
uint32_t spacer_count = 0;
dbgTrace(D_WAAP) << "decodeBase64Chunk: value='" << value << "' match='" << string(it, end) << "'";
@@ -1047,9 +1048,12 @@ bool decodeBase64Chunk(
acc_bits -= 8;
// Count non-printable characters seen
if (!isprint(code)) {
if (!isprint(code) && (code != '\n') && (code != '\t')) {
nonPrintableCharsCount++;
}
if (code == '\r') {
spacer_count++;
}
decoded += (char)code;
}
@@ -1059,12 +1063,24 @@ bool decodeBase64Chunk(
// end of encoded sequence decoded.
dbgTrace(D_WAAP_BASE64) << "decodeBase64Chunk: decoded.size=" << decoded.size() <<
", nonPrintableCharsCount=" << nonPrintableCharsCount << "; decoded='" << decoded << "'";
dbgTrace(D_WAAP_BASE64)
<< "decodeBase64Chunk: decoded.size="
<< decoded.size()
<< ", nonPrintableCharsCount="
<< nonPrintableCharsCount
<< ", spacer_count = "
<< spacer_count
<< ", decoded size = "
<< decoded.size()
<< "; decoded='"
<< decoded << "'";
// Return success only if decoded.size>=5 and there are less than 10% of non-printable
// characters in output.
if (decoded.size() >= 5) {
if (spacer_count > 1) {
nonPrintableCharsCount = nonPrintableCharsCount - spacer_count + 1;
}
if (nonPrintableCharsCount * 10 < decoded.size()) {
dbgTrace(D_WAAP_BASE64) << "decodeBase64Chunk: (decode/replace) decoded.size=" << decoded.size() <<
", nonPrintableCharsCount=" << nonPrintableCharsCount << ": replacing with decoded data";
@@ -1074,6 +1090,8 @@ bool decodeBase64Chunk(
", nonPrintableCharsCount=" << nonPrintableCharsCount;
decoded.clear();
}
dbgTrace(D_WAAP_BASE64) << "returning true: successfully decoded."
<< " Returns decoded data in \"decoded\" parameter";
return true; // successfully decoded. Returns decoded data in "decoded" parameter
}

View File

@@ -41,7 +41,11 @@ public:
virtual std::chrono::microseconds getTimeoutVal() const = 0;
virtual std::string getProfileId(const std::string &tenant_id, const std::string &region) const = 0;
virtual std::vector<std::string> getProfileId(
const std::string &tenant_id,
const std::string &region,
const std::string &account_id = ""
) const = 0;
private:
friend class LoadNewTenants;

View File

@@ -25,7 +25,10 @@ public:
MOCK_CONST_METHOD2(areTenantAndProfileActive, bool(const std::string &, const std::string &));
MOCK_METHOD2(addActiveTenantAndProfile, void(const std::string &, const std::string &));
MOCK_METHOD2(deactivateTenant, void(const std::string &, const std::string &));
MOCK_CONST_METHOD2(getProfileId, std::string(const std::string &, const std::string &));
MOCK_CONST_METHOD3(
getProfileId,
std::vector<std::string>(const std::string &, const std::string &, const std::string &)
);
MOCK_CONST_METHOD0(getTimeoutVal, std::chrono::microseconds());

View File

@@ -147,6 +147,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_IOT_ENFORCE_POLICY, D_IOT_ENFORCE)
DEFINE_FLAG(D_IOT_ENFORCE_ASSETS, D_IOT_ENFORCE)
DEFINE_FLAG(D_IOT_DOCTOR, D_IOT_NEXT)
DEFINE_FLAG(D_IOT_RISK, D_IOT_NEXT)
DEFINE_FLAG(D_IOT_DISCOVERY, D_IOT_NEXT)
DEFINE_FLAG(D_IOT_DISCOVERY_UTILS, D_IOT_DISCOVERY)
DEFINE_FLAG(D_IOT_PROBE, D_IOT_DISCOVERY_UTILS)

View File

@@ -69,6 +69,7 @@ enum class AudienceTeam
AGENT_INTELLIGENCE,
CPVIEW_MONITORING,
SIGNATURE_DEVELOPERS,
FILE_UPLOAD,
IDENTITY_AWARENESS,
NONE,
@@ -140,6 +141,7 @@ enum class IssuingEngine {
AGENT_CORE,
IOT_NEXT,
SDWAN,
FILE_UPLOAD,
IDA_NEXT
};

View File

@@ -441,6 +441,7 @@ void
MainloopComponent::Impl::yield(bool force)
{
dbgAssert(curr_iter != routines.end()) << "Calling 'yield' without a running current routine";
if (do_stop) throw MainloopStop();
if (!force && getTimer()->getMonotonicTime() < stop_time) return;
auto env = Singleton::Consume<I_Environment>::by<MainloopComponent>()->saveEnvironment();

View File

@@ -242,8 +242,8 @@ TagAndEnumManagement::convertToString(const Notification &notification)
case Notification::SYNC_LEARNING: return "b9b9ab04-2e2a-4cd1-b7e5-2c956861fb69";
case Notification::SDWAN_POLICY_UPDATE: return "2b18f5a0-5503-4c6b-967f-aa71dbced1aa";
case Notification::SDWAN_POLICY_UPDATE_ERROR: return "8d2db6ea-30b7-11ec-8d3d-0242ac130003";
case Notification::SDWAN_POLICY_UPDATE_LOG: return "f3a4fa06-2d91-41bc-84cd-7e9eaa9f4ce3";
case Notification::SDWAN_POLICY_UPDATE_ERROR_LOG: return "5529d385-44ed-46d6-b8d0-1b8a99b4fbea";
case Notification::SDWAN_POLICY_UPDATE_LOG: return "97cb79e1-e873-4f28-b123-5e19f8dd6f99";
case Notification::SDWAN_POLICY_UPDATE_ERROR_LOG: return "44ca5755-07a2-483c-b756-b7df444e175c";
}
dbgAssert(false) << "Reached impossible notification value of: " << static_cast<int>(notification);
@@ -257,6 +257,7 @@ TagAndEnumManagement::convertToString(const IssuingEngine &issuing_engine)
case IssuingEngine::AGENT_CORE: return "Agent Core";
case IssuingEngine::IOT_NEXT: return "iotNext";
case IssuingEngine::SDWAN: return "sdwanGwSharing";
case IssuingEngine::FILE_UPLOAD: return "fileUpload";
case IssuingEngine::IDA_NEXT: return "quantumMetaNotifyIdn";
}

View File

@@ -27,6 +27,46 @@ using namespace std;
USE_DEBUG_FLAG(D_TENANT_MANAGER);
class AccountRegionPair
{
public:
void
load(cereal::JSONInputArchive &ar)
{
ar(
cereal::make_nvp("accountId", accountID),
cereal::make_nvp("regionName", regionName)
);
}
bool
operator<(const AccountRegionPair &other) const {
return accountID < other.getAccountID() && regionName < other.getRegion();
}
const string & getAccountID() const { return accountID; }
const string & getRegion() const { return regionName; }
private:
string accountID;
string regionName;
};
class AccountRegionSet
{
public:
void
load(cereal::JSONInputArchive &ar)
{
cereal::load(ar, account_region_map);
}
const set<AccountRegionPair> & getAccoutRegionPairs() const { return account_region_map; }
private:
set<AccountRegionPair> account_region_map;
};
class TenantManager::Impl
:
Singleton::Provide<I_TenantManager>::From<TenantManager>
@@ -49,7 +89,7 @@ public:
chrono::microseconds getTimeoutVal() const override;
string getProfileId(const string &tenant_id, const string &region) const override;
vector<string> getProfileId(const string &tenant_id, const string &region, const string &account) const override;
void
addInstance(const string &tenant_id, const string &profile_id, const string &instace_id)
@@ -338,12 +378,13 @@ TenantManager::Impl::getProfileIds(const string &_tenant_id) const
return tenant_id.profile_ids.get();
}
string
TenantManager::Impl::getProfileId(const string &tenant_id, const string &region) const
vector<string>
TenantManager::Impl::getProfileId(const string &tenant_id, const string &region, const string &account_id = "") const
{
if (region.empty()) {
dbgWarning(D_TENANT_MANAGER) << "Can't find the profile ID. Region is empty";
return "";
return vector<string>();
}
vector<string> profile_ids = fetchProfileIds(tenant_id);
@@ -352,36 +393,62 @@ TenantManager::Impl::getProfileId(const string &tenant_id, const string &region)
auto i_env = Singleton::Consume<I_Environment>::by<TenantManager>();
auto unset_tenant_on_exit = make_scope_exit([&]() { i_env->unsetActiveTenantAndProfile(); });
vector<string> profiles_to_return;
for (const string &profile_id : profile_ids) {
string account_dbg = account_id.empty() ? "" : (" in the account " + account_id);
dbgDebug(D_TENANT_MANAGER)
<< "Checking if the profile ID: "
<< profile_id
<< " corresponds to the tenant ID: "
<< tenant_id
<< " and the region "
<< region;
<< region
<< account_dbg;
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
auto maybe_region = getSetting<string>("region");
if (maybe_region.ok() && region == maybe_region.unpack()) {
dbgDebug(D_TENANT_MANAGER) << "The region corresponds to profile ID " << profile_id;
return profile_id;
auto maybe_account_region_set = getSetting<AccountRegionSet>("accountRegionSet");
if (maybe_account_region_set.ok()) {
auto account_region_set = maybe_account_region_set.unpack().getAccoutRegionPairs();
if (account_region_set.empty()) {
dbgTrace(D_TENANT_MANAGER) << "Old profile with new hook. Resolving to profile ID: " << profile_id;
profiles_to_return.push_back(profile_id);
return profiles_to_return;
}
for (const AccountRegionPair &account : account_region_set) {
if (region == account.getRegion() && (account_id.empty() || account_id == account.getAccountID())) {
dbgTrace(D_TENANT_MANAGER) << "Found a corresponding profile ID: " << profile_id;
profiles_to_return.push_back(profile_id);
}
}
} else {
if (maybe_region.ok()) {
dbgTrace(D_TENANT_MANAGER)
<< "The region does not corresponds to profile ID "
<< profile_id
<< " region "
<< *maybe_region;
auto maybe_region = getSetting<string>("region");
if (maybe_region.ok() && region == maybe_region.unpack()) {
dbgDebug(D_TENANT_MANAGER) << "The region corresponds to profile ID " << profile_id;
profiles_to_return.push_back(profile_id);
return profiles_to_return;
} else {
dbgDebug(D_TENANT_MANAGER) << "Failed to get region for profile ID " << profile_id;
if (maybe_region.ok()) {
dbgTrace(D_TENANT_MANAGER)
<< "The region does not corresponds to profile ID "
<< profile_id
<< " region "
<< *maybe_region;
} else {
dbgDebug(D_TENANT_MANAGER) << "Failed to match profile ID by accountRegionSet or region";
}
}
}
}
dbgWarning(D_TENANT_MANAGER) << "Found no profile ID for tenant " << tenant_id << " and region " << region;
return "";
if (!profiles_to_return.empty()) {
dbgDebug(D_TENANT_MANAGER) << "Found " << profiles_to_return.size() << " profiles that correspond";
return profiles_to_return;
}
dbgWarning(D_TENANT_MANAGER) << "Found no corresponding profile ID";
return vector<string>();
}
void
@@ -520,5 +587,6 @@ TenantManager::preload()
{
registerExpectedConfiguration<uint32_t>("Tenant Manager", "Tenant timeout");
registerExpectedConfiguration<string>("Tenant Manager", "Tenant manager type");
registerExpectedSetting<AccountRegionSet>("accountRegionSet");
registerExpectedSetting<string>("region");
}

View File

@@ -121,8 +121,11 @@ INSTALL(FILES
JsonVisitor.h
${BISON_LOCATION_HEADER}
DESTINATION include/graphqlparser)
if (0)
INSTALL(TARGETS graphqlparser
LIBRARY DESTINATION lib)
endif()
if (UNIX)
# generate pkgconfig file

View File

@@ -78,6 +78,7 @@ enum class Service {
SDWAN_LOGGER,
IOT_ENFORCE,
IOT_DOCTOR,
IOT_RISK,
IOT_GW_SENSOR,
IOT_SNMP,
IOT_MS_DHCP,
@@ -152,6 +153,7 @@ getServiceString(const Service service)
case (Service::CAPSULE8): return "capsule8";
case (Service::IOT_ENFORCE): return "iot-enforce";
case (Service::IOT_DOCTOR): return "iot-doctor";
case (Service::IOT_RISK): return "iot-risk";
case (Service::IOT_GW_SENSOR): return "iot-gw-sensor";
case (Service::IOT_SNMP): return "iot-snmp";
case (Service::IOT_MS_DHCP): return "iot-ms-dhcp";
@@ -267,6 +269,11 @@ getServiceConfig (const Service service)
filesystem_path + "/conf/cp-nano-iot-doctor-debug-conf.json",
log_files_path + "/nano_agent/cp-nano-iot-doctor.dbg"
);
case (Service::IOT_RISK):
return ServiceConfig(
filesystem_path + "/conf/cp-nano-iot-risk-debug-conf.json",
log_files_path + "/nano_agent/cp-nano-iot-risk.dbg"
);
case (Service::IOT_GW_SENSOR):
return ServiceConfig(
filesystem_path + "/conf/cp-nano-iot-gw-sensor-debug-conf.json",
@@ -1246,6 +1253,8 @@ extractServices(const vector<string> &args)
services.push_back(Service::IOT_ENFORCE);
} else if (getServiceString(Service::IOT_DOCTOR).find(maybe_service) == 0) {
services.push_back(Service::IOT_DOCTOR);
} else if (getServiceString(Service::IOT_RISK).find(maybe_service) == 0) {
services.push_back(Service::IOT_RISK);
} else if (getServiceString(Service::IOT_GW_SENSOR).find(maybe_service) == 0) {
services.push_back(Service::IOT_GW_SENSOR);
} else if (getServiceString(Service::IOT_SNMP).find(maybe_service) == 0) {

View File

@@ -1565,26 +1565,39 @@ stop_service() # Initials - stops
exit 255
}
record_command() # Initials - rc
{
touch /var/log/nano_agent/operations.log
echo "$(tail -99 /var/log/nano_agent/operations.log)" > /var/log/nano_agent/operations.log
echo $(date "+%Y.%m.%d-%H.%M.%S") ": " $0 $@ >> /var/log/nano_agent/operations.log
}
run() # Initials - r
{
r_deprecated_msg="Option ${1} is deprecated. Please use"
if [ -z "$1" ]; then
usage
elif [ "--debug" = "$1" ] || [ "-d" = "$1" ]; then
record_command $@
run_cpnano_debug "cpnano" "$@"
elif [ "--display-policy" = "$1" ] || [ "-dp" = "$1" ]; then
record_command $@
run_display_policy
elif [ "--status" = "$1" ] || [ "-s" = "$1" ]; then
record_command $@
run_status
if [ "--extended" = "$2" ]; then
shift
run_health_check "${@}"
fi
elif [ "--start-agent" = "$1" ] || [ "-r" = "$1" ]; then
record_command $@
run_start_agent
elif [ "--stop-agent" = "$1" ] || [ "-q" = "$1" ]; then
record_command $@
run_stop_agent
elif [ "--uninstall" = "$1" ] || [ "-u" = "$1" ]; then
record_command $@
uninstall_agent
elif [ "--display-settings" = "$1" ]; then
echo "${r_deprecated_msg} --display-config"
@@ -1595,42 +1608,56 @@ run() # Initials - r
elif [ "-ls" = "$1" ]; then
echo "${r_deprecated_msg} -lc"
elif [ "--display-config" = "$1" ] || [ "-dc" = "$1" ]; then
record_command $@
shift
run_display_settings "${@}"
elif [ "--load-config" = "$1" ] || [ "-lc" = "$1" ]; then
record_command $@
shift
run_load_settings "${@}"
elif [ "--set-proxy" = "$1" ] || [ "-sp" = "$1" ]; then
record_command $@
shift
set_proxy "${@}"
elif [ "--set-gradual-policy" = "$1" ] || [ "-gp" = "$1" ]; then
record_command $@
shift
run_update_gradual_policy "set" "${@}"
elif [ "--delete-gradual-policy" = "$1" ] || [ "-dg" = "$1" ]; then
record_command $@
shift
run_update_gradual_policy "delete" "${@}"
elif [ "--set-traffic-recording-policy" = "$1" ] || [ "-tr" = "$1" ]; then
record_command $@
shift
run_set_traffic_recording_policy "${@}"
elif [ "--cp-agent-info" = "$1" ] || [ "-ai" = "$1" ]; then
record_command $@
shift
run_ai "${@}"
elif [ "--update-certs" = "$1" ] || [ "-uc" = "$1" ]; then
record_command $@
run_set_ca_directory "$2"
elif [ "--set-public-key" = "$1" ] || [ "-pk" = "$1" ]; then
record_command $@
run_set_publick_key "$2"
elif [ "--print-metrics" = "$1" ] || [ "-pm" = "$1" ]; then
record_command $@
run_print_metrics "$2"
elif [ "--stop-service" = "$1" ] || [ "-qs" = "$1" ]; then
record_command $@
shift
stop_service "${@}"
elif [ "--start-service" = "$1" ] || [ "-rs" = "$1" ]; then
record_command $@
shift
start_service "${@}"
elif [ "--set-mode" = "$1" ] || [ "-sm" = "$1" ]; then
record_command $@
shift
set_mode "${@}"
elif [ "-vp" = "$1" ] || [ "--view-policy" = "$1" ]; then
record_command $@
shift
var_policy_file=$1
if [ -z ${var_policy_file} ]; then
@@ -1638,6 +1665,7 @@ run() # Initials - r
fi
less ${var_policy_file}
elif [ "-ep" = "$1" ] || [ "--edit-policy" = "$1" ]; then
record_command $@
shift
var_policy_file=$1
if [ -z ${var_policy_file} ]; then
@@ -1645,12 +1673,20 @@ run() # Initials - r
fi
vi ${var_policy_file}
elif [ "-ap" = "$1" ] || [ "--apply-policy" = "$1" ]; then
record_command $@
curl_apply_policy=$(${curl_cmd} -S -w "%{http_code}\n" -m 1 --noproxy "*" --header "Content-Type: application/json" \
--request POST --data {} http://127.0.0.1:"$(extract_api_port 'orchestration')"/set-apply-policy 2>&1)
while [ /etc/cp/conf/local_policy.yaml -nt /etc/cp/conf/policy.json ]; do
echo -n "."
sleep 3
done
echo "New policy applied."
exit 1
elif [ "-lp" = "$1" ] || [ "--list-policies" = "$1" ]; then
record_command $@
echo "/etc/cp/conf/local_policy.yaml"
elif [ "-vl" = "$1" ] || [ "--view-logs" = "$1" ]; then
record_command $@
less /var/log/nano_agent/cp-nano-http-transaction-handler.log?
else
usage

View File

@@ -50,6 +50,7 @@ var_sleep_interval=30
var_error_sleep_interval=30
var_upgrade_mode=
var_token=
var_email=
var_installation_debug_mode=false
var_startup_service=
var_arch_flag=
@@ -132,6 +133,7 @@ usage()
echo "--uninstall : Remove Nano Agent"
echo "--token <token> : Registration token"
echo "--fog <fog URL> : Fog Address"
echo "--email <email address> : Contact Information"
echo "--certs-dir <Trusted CA directory> : Path to the trusted CA directory"
echo "--public-key <Public key file path> : Path to the SSL certificate's public key file (PEM format)"
echo "--ignore <ignore packages list> : List of ignored packages"
@@ -222,6 +224,9 @@ while true; do
elif [ "$1" = "--token" ]; then
shift
OTP_TOKEN=$1
elif [ "$1" = "--email" ]; then
shift
var_email=$1
elif [ "$1" = "--offline_mode" ]; then
var_offline_mode=true
var_orchestration_mode="offline_mode"
@@ -891,7 +896,8 @@ install_orchestration()
cp_print "Building the default policy json"
echo '{"'$ORCHESTRATION_NAME'": { "fog-address":"'$var_fog_address'", ' > ${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
echo '"pulling-interval":'$var_sleep_interval', ' >> ${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
echo '"error-pulling-interval":'$var_error_sleep_interval'}}' >> ${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
echo '"error-pulling-interval":'$var_error_sleep_interval'},' >> ${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
echo '"registration-data": { "email-address": "'$var_email'"}}' >> ${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
copy_orchestration_executable
copy_k8s_executable