First release of open-appsec source code

This commit is contained in:
roybarda
2022-10-26 19:33:19 +03:00
parent 3883109caf
commit a883352f79
1353 changed files with 276290 additions and 1 deletions

View File

@@ -0,0 +1,3 @@
add_library(agent_details agent_details.cc)
add_subdirectory(agent_details_ut)

View File

@@ -0,0 +1,307 @@
// 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 "agent_details.h"
#include <fstream>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include "config.h"
#include "debug.h"
#include "sasal.h"
SASAL_START // Orchestration - Communication
using namespace std;
USE_DEBUG_FLAG(D_ORCHESTRATOR);
const map<string, I_AgentDetails::MachineType> AgentDetails::machineTypes({
{ "Amazon EC2", I_AgentDetails::MachineType::AWS },
{ "Xen", I_AgentDetails::MachineType::AWS },
{ "Microsoft Corporation", I_AgentDetails::MachineType::AZURE },
{ "VMware, Inc.", I_AgentDetails::MachineType::ON_PREM }
});
void
AgentDetails::init()
{
registerMachineType();
}
bool
AgentDetails::readAgentDetails()
{
auto agent_details_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/agent_details.json",
"Agent details",
"File path"
);
ifstream file(agent_details_path);
if (!file.is_open()) {
dbgWarning(D_ORCHESTRATOR) << "Agent details file does not exist. File: " << agent_details_path;
return false;
}
stringstream file_stream;
try {
file_stream << file.rdbuf();
cereal::JSONInputArchive archive_in(file_stream);
serialize(archive_in);
} catch (exception &e) {
dbgWarning(D_ORCHESTRATOR) << "Failed to parse agent details."
<< " File: " << agent_details_path
<< ", Error: " << e.what();
return false;
}
file.close();
return true;
}
bool
AgentDetails::writeAgentDetails()
{
auto agent_details_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/agent_details.json",
"Agent details",
"File path"
);
try {
ofstream ostream(agent_details_path);
cereal::JSONOutputArchive archive_out(ostream);
serialize(archive_out);
} catch (exception &e) {
dbgWarning(D_ORCHESTRATOR) << "Failed to write the agent details."
<< " File: " << agent_details_path
<< ", Error: " << e.what();
return false;
}
return true;
}
void
AgentDetails::serialize(cereal::JSONOutputArchive &ar)
{
ar(cereal::make_nvp("Fog domain", fog_domain));
ar(cereal::make_nvp("Agent ID", agent_id));
ar(cereal::make_nvp("Fog port", fog_port));
ar(cereal::make_nvp("Tenant ID", tenant_id));
ar(cereal::make_nvp("Profile ID", profile_id));
ar(cereal::make_nvp("Encrypted connection", encrypted_connection));
ar(cereal::make_nvp("OpenSSL certificates directory", openssl_dir));
try {
ar(cereal::make_nvp("Proxy", proxy));
} catch (...) {
ar.setNextName(nullptr);
}
try {
ar(cereal::make_nvp("Cluster ID", cluster_id));
} catch (...) {
ar.setNextName(nullptr);
}
try {
static const EnumArray<OrchestrationMode, std::string> orchestraiton_mode_str {
"online_mode",
"offline_mode",
"hybrid_mode"
};
std::string orchestraiton_mode_string = orchestraiton_mode_str[orchestration_mode];
ar(cereal::make_nvp("Orchestration mode", orchestraiton_mode_string));
bool is_offline_mode = (orchestration_mode == OrchestrationMode::OFFLINE);
ar(cereal::make_nvp("Is Offline Mode", is_offline_mode));
} catch (...) {
ar.setNextName(nullptr);
}
}
void
AgentDetails::serialize(cereal::JSONInputArchive &ar)
{
ar(cereal::make_nvp("Fog domain", fog_domain));
ar(cereal::make_nvp("Agent ID", agent_id));
ar(cereal::make_nvp("Fog port", fog_port));
ar(cereal::make_nvp("Tenant ID", tenant_id));
ar(cereal::make_nvp("Profile ID", profile_id));
ar(cereal::make_nvp("Encrypted connection", encrypted_connection));
ar(cereal::make_nvp("OpenSSL certificates directory", openssl_dir));
try {
ar(cereal::make_nvp("Proxy", proxy));
} catch (...) {
ar.setNextName(nullptr);
}
try {
ar(cereal::make_nvp("Cluster ID", cluster_id));
if (!cluster_id.empty()) {
Singleton::Consume<I_Environment>::by<AgentDetails>()->getConfigurationContext().registerValue<string>(
"k8sClusterId",
cluster_id,
EnvKeyAttr::LogSection::SOURCE
);
}
} catch (...) {
ar.setNextName(nullptr);
}
try {
static const std::map<std::string, OrchestrationMode> orchestrationModeMap {
{ "online_mode", OrchestrationMode::ONLINE },
{ "offline_mode", OrchestrationMode::OFFLINE },
{ "hybrid_mode", OrchestrationMode::HYBRID }
};
std::string orchestraiton_mode_string;
ar(cereal::make_nvp("Orchestration mode", orchestraiton_mode_string));
auto iter = orchestrationModeMap.find(orchestraiton_mode_string);
if (iter != orchestrationModeMap.end()) {
orchestration_mode = iter->second;
}
} catch (...) {
try {
bool is_offline_mode = false;
ar(cereal::make_nvp("Is Offline Mode", is_offline_mode));
if (is_offline_mode) {
orchestration_mode = OrchestrationMode::OFFLINE;
} else {
orchestration_mode = OrchestrationMode::ONLINE;
}
} catch (...) {
ar.setNextName(nullptr);
}
}
}
string
AgentDetails::getAgentId() const
{
static string default_agent_id = "Unknown";
if (agent_id.empty()) return default_agent_id;
return agent_id;
}
Maybe<string>
AgentDetails::getProxy() const
{
if (proxy == "") return genError("Proxy not set");
return proxy;
}
Maybe<uint16_t>
AgentDetails::getFogPort() const
{
if (fog_port == 0) return genError("Fog port is unset");
return fog_port;
}
Maybe<string>
AgentDetails::getFogDomain() const
{
if (fog_domain.empty()) return genError("Fog domain is unset");
return fog_domain;
}
void
AgentDetails::setClusterId(const std::string &_cluster_id)
{
dbgTrace(D_ORCHESTRATOR) << "Setting Cluster Id in the agent details. Cluster ID: " << _cluster_id;
cluster_id = _cluster_id;
writeAgentDetails();
}
void
AgentDetails::preload()
{
registerExpectedConfiguration<string>("orchestration", "Agent details path");
registerConfigLoadCb([this] () { readAgentDetails(); });
}
string
AgentDetails::getTenantId() const
{
return tenant_id;
}
string
AgentDetails::getProfileId() const
{
return profile_id;
}
string
AgentDetails::getClusterId() const
{
return cluster_id;
}
Maybe<string>
AgentDetails::getOpenSSLDir() const
{
if (openssl_dir.empty()) return genError("OpenSSL certificates directory was not set");
return openssl_dir;
}
OrchestrationMode
AgentDetails::getOrchestrationMode() const
{
return orchestration_mode;
}
Maybe<I_AgentDetails::MachineType>
AgentDetails::getMachineTypeFromDmiTable()
{
static const string decode_machine_type_cmd = "dmidecode -s system-manufacturer | tr -d '\\n'";
I_ShellCmd *i_shell_cmd = Singleton::Consume<I_ShellCmd>::by<AgentDetails>();
auto machine_type = i_shell_cmd->getExecOutput(decode_machine_type_cmd);
if (!machine_type.ok()) {
dbgWarning(D_ORCHESTRATOR) << "Error. Could not decode the DMI table. " << machine_type.getErr();
return I_AgentDetails::MachineType::UNRECOGNIZED;
} else if (machine_type.unpack().empty()) {
dbgWarning(D_ORCHESTRATOR) << "Error. Could not decode the DMI table. Table value is empty";
return I_AgentDetails::MachineType::UNRECOGNIZED;
}
dbgInfo(D_ORCHESTRATOR) << "Decoded the DMI talble: " << machine_type.unpack();
auto resolved_machine_type = machineTypes.find(*machine_type);
if (resolved_machine_type == end(machineTypes)) return I_AgentDetails::MachineType::UNRECOGNIZED;
return resolved_machine_type->second;
}
void
AgentDetails::registerMachineType()
{
Maybe<I_AgentDetails::MachineType> machine_type = getMachineTypeFromDmiTable();
if (!machine_type.ok()) {
dbgWarning(D_ORCHESTRATOR)
<< "Error. Could not get machine type from the DMI table. "
<< machine_type.getErr();
return;
}
if (machine_type.unpack() == I_AgentDetails::MachineType::UNRECOGNIZED) {
dbgWarning(D_ORCHESTRATOR) << "Error. Machine type is unrecognized";
}
Singleton::Consume<I_Environment>::by<AgentDetails>()->registerValue<I_AgentDetails::MachineType>(
"MachineType", machine_type.unpack()
);
dbgInfo(D_ORCHESTRATOR) << "Setting machine type " << static_cast<int>(machine_type.unpack());
}
SASAL_END

View File

@@ -0,0 +1,9 @@
include_directories(${CMAKE_SOURCE_DIR}/components/include)
include_directories(${CMAKE_SOURCE_DIR}/cptest/include)
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
agent_details_ut
"agent_details_ut.cc"
"singleton;config;agent_details;environment;metric;event_is;-lboost_regex"
)

View File

@@ -0,0 +1,156 @@
#include "agent_details.h"
#include "mock/mock_encryptor.h"
#include "mock/mock_shell_cmd.h"
#include "cptest.h"
#include "config.h"
#include "config_component.h"
#include "buffer.h"
#include "cptest.h"
using namespace std;
using namespace testing;
class AgentDetailsTest : public Test
{
public:
AgentDetailsTest()
{
config = Singleton::Consume<Config::I_Config>::from(conf);
}
::Environment env;
ConfigComponent conf;
StrictMock<MockEncryptor> mock_encryptor;
StrictMock<MockShellCmd> mock_shell_cmd;
Config::I_Config *config = nullptr;
};
TEST_F(AgentDetailsTest, doNothing)
{
}
TEST_F(AgentDetailsTest, basicTest)
{
const vector<string> agent_details_vec {
"{",
" \"Fog domain\": \"fog.com\",",
" \"Agent ID\": \"fdfdf-5454-dfd\",",
" \"Fog port\": 443,",
" \"Encrypted connection\": false,",
" \"Orchestration mode\": \"offline_mode\",",
" \"Tenant ID\": \"tenant_id\",",
" \"Profile ID\": \"profile\",",
" \"Proxy\": \"http://proxy.checkpoint.com/\",",
" \"OpenSSL certificates directory\": \"\"",
"}"
};
AgentDetails agent_details;
env.preload();
agent_details.preload();
EXPECT_CALL(
mock_shell_cmd,
getExecOutput("dmidecode -s system-manufacturer | tr -d '\\n'", _, _)
).WillOnce(Return(string("Microsoft Corporation")));
env.init();
agent_details.init();
auto i_conf = Singleton::Consume<Config::I_Config>::from(conf);
i_conf->reloadConfiguration();
CPTestTempfile agent_details_file(agent_details_vec);
setConfiguration(agent_details_file.fname, "Agent details", "File path");
EXPECT_TRUE(agent_details.readAgentDetails());
EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.com");
EXPECT_EQ(agent_details.getFogPort().unpack(), 443);
EXPECT_EQ(agent_details.getAgentId(), "fdfdf-5454-dfd");
EXPECT_FALSE(agent_details.getSSLFlag());
agent_details.setSSLFlag(true);
agent_details.setFogPort(80);
agent_details.setFogDomain("fog.checkpoint.com");
agent_details.setAgentId("dfdfdf-dfd");
agent_details.setClusterId("d5bd7949-554e-4fac-86c3-6e4e5d46a034");
EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.checkpoint.com");
EXPECT_EQ(agent_details.getFogPort().unpack(), 80);
EXPECT_EQ(agent_details.getAgentId(), "dfdfdf-dfd");
EXPECT_EQ(agent_details.getTenantId(), "tenant_id");
EXPECT_EQ(agent_details.getProfileId(), "profile");
EXPECT_EQ(agent_details.getClusterId(), "d5bd7949-554e-4fac-86c3-6e4e5d46a034");
EXPECT_TRUE(agent_details.writeAgentDetails());
EXPECT_TRUE(agent_details.readAgentDetails());
EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.checkpoint.com");
EXPECT_EQ(agent_details.getFogPort().unpack(), 80);
EXPECT_EQ(agent_details.getAgentId(), "dfdfdf-dfd");
EXPECT_EQ(agent_details.getClusterId(), "d5bd7949-554e-4fac-86c3-6e4e5d46a034");
EXPECT_TRUE(agent_details.getSSLFlag());
EXPECT_THAT(agent_details.getProxy(), IsValue("http://proxy.checkpoint.com/"));
agent_details.setProxy("none");
EXPECT_THAT(agent_details.getProxy(), IsValue("none"));
EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE);
agent_details.setOrchestrationMode(OrchestrationMode::ONLINE);
EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::ONLINE);
auto machine_type = Singleton::Consume<I_Environment>::from(env)->get<I_AgentDetails::MachineType>("MachineType");
EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::AZURE);
}
TEST_F(AgentDetailsTest, openSSL)
{
const vector<string> agent_details_vec {
"{",
" \"Fog domain\": \"fog.com\",",
" \"Agent ID\": \"fdfdf-5454-dfd\",",
" \"Fog port\": 443,",
" \"Encrypted connection\": false,",
" \"Tenant ID\": \"tenant_id\",",
" \"Profile ID\": \"profile\",",
" \"OpenSSL certificates directory\": \"\"",
"}"
};
AgentDetails agent_details;
agent_details.preload();
CPTestTempfile agent_details_file(agent_details_vec);
setConfiguration(agent_details_file.fname, "Agent details", "File path");
EXPECT_FALSE(agent_details.getSSLFlag());
EXPECT_THAT(agent_details.getOpenSSLDir(), IsError("OpenSSL certificates directory was not set"));
agent_details.setOpenSSLDir("a/b/c");
EXPECT_THAT(agent_details.getOpenSSLDir(), IsValue("a/b/c"));
agent_details.setFogPort(10);
agent_details.setSSLFlag(false);
agent_details.setFogDomain("www.fog.checkpoint.com");
agent_details.setOpenSSLDir("");
EXPECT_THAT(agent_details.getFogPort(), IsValue(10));
EXPECT_FALSE(agent_details.getSSLFlag());
EXPECT_THAT(agent_details.getFogDomain(), IsValue("www.fog.checkpoint.com"));
EXPECT_THAT(agent_details.getOpenSSLDir(), IsError("OpenSSL certificates directory was not set"));
EXPECT_FALSE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE);
agent_details.setOrchestrationMode(OrchestrationMode::OFFLINE);
EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE);
}
TEST_F(AgentDetailsTest, unrecognizedMachineType)
{
env.preload();
env.init();
AgentDetails agent_details;
EXPECT_CALL(
mock_shell_cmd,
getExecOutput("dmidecode -s system-manufacturer | tr -d '\\n'", _, _)
).WillOnce(Return(string("Skynet")));
agent_details.preload();
agent_details.init();
auto machine_type = Singleton::Consume<I_Environment>::from(env)->get<I_AgentDetails::MachineType>("MachineType");
EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::UNRECOGNIZED);
}