Island: Collect system info in server_setup.py

Information about the system (host machine, island, etc.) should be
collected early on and passed to the components that require it.
This commit is contained in:
Mike Salvatore 2022-08-12 11:42:31 -04:00
parent 1873ce3bfe
commit 09f6cce6de
2 changed files with 40 additions and 39 deletions

View File

@ -3,6 +3,7 @@ import json
import logging import logging
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Sequence, Tuple
import gevent.hub import gevent.hub
import requests import requests
@ -27,6 +28,7 @@ from monkey_island.cc.arg_parser import parse_cli_args # noqa: E402
from monkey_island.cc.server_utils.consts import ( # noqa: E402 from monkey_island.cc.server_utils.consts import ( # noqa: E402
GEVENT_EXCEPTION_LOG, GEVENT_EXCEPTION_LOG,
MONGO_CONNECTION_TIMEOUT, MONGO_CONNECTION_TIMEOUT,
MONKEY_ISLAND_ABS_PATH,
) )
from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402
from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402
@ -50,7 +52,9 @@ def run_monkey_island():
_exit_on_invalid_config_options(config_options) _exit_on_invalid_config_options(config_options)
_configure_logging(config_options) _configure_logging(config_options)
container = _initialize_di_container(config_options.data_dir) ip_addresses, deployment, version = _collect_system_info()
_send_analytics(deployment, version)
container = _initialize_di_container(ip_addresses, version, config_options.data_dir)
_initialize_mongodb_connection(config_options.start_mongodb, config_options.data_dir) _initialize_mongodb_connection(config_options.start_mongodb, config_options.data_dir)
_start_island_server(island_args.setup_only, config_options, container) _start_island_server(island_args.setup_only, config_options, container)
@ -85,8 +89,39 @@ def _configure_logging(config_options):
setup_logging(config_options.data_dir, config_options.log_level) setup_logging(config_options.data_dir, config_options.log_level)
def _initialize_di_container(data_dir: Path) -> DIContainer: def _collect_system_info() -> Tuple[Sequence[str], Deployment, Version]:
return initialize_services(data_dir) deployment = _get_deployment()
version = Version(get_version(), deployment)
return (get_ip_addresses(), deployment, version)
def _get_deployment() -> Deployment:
deployment_file_path = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "deployment.json"
try:
with open(deployment_file_path, "r") as deployment_info_file:
deployment_info = json.load(deployment_info_file)
return Deployment[deployment_info["deployment"].upper()]
except KeyError as err:
raise Exception(
f"The deployment file ({deployment_file_path}) did not contain the expected data: "
f"missing key {err}"
)
except Exception as err:
raise Exception(f"Failed to fetch the deployment from {deployment_file_path}: {err}")
def _initialize_di_container(
ip_addresses: Sequence[str], version: Version, data_dir: Path
) -> DIContainer:
container = DIContainer()
container.register_convention(Sequence[str], "ip_addresses", ip_addresses)
container.register_instance(Version, version)
container.register_convention(Path, "data_dir", data_dir)
initialize_services(container, data_dir)
return container
def _initialize_mongodb_connection(start_mongodb: bool, data_dir: Path): def _initialize_mongodb_connection(start_mongodb: bool, data_dir: Path):
@ -145,7 +180,6 @@ def _start_island_server(
error_log=logger, error_log=logger,
) )
_log_init_info() _log_init_info()
_send_analytics(container)
http_server.serve_forever() http_server.serve_forever()
@ -189,9 +223,7 @@ ANALYTICS_URL = (
) )
def _send_analytics(di_container): def _send_analytics(deployment: Deployment, version: Version):
version = di_container.resolve(Version)
deployment = di_container.resolve(Deployment)
url = ANALYTICS_URL.format(deployment=deployment.value, version=version.version_number) url = ANALYTICS_URL.format(deployment=deployment.value, version=version.version_number)
try: try:
response = requests.get(url).json() response = requests.get(url).json()

View File

@ -1,7 +1,5 @@
import json
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Sequence
from pubsub.core import Publisher from pubsub.core import Publisher
from pymongo import MongoClient from pymongo import MongoClient
@ -16,9 +14,6 @@ from common.aws import AWSInstance
from common.common_consts.telem_categories import TelemCategoryEnum from common.common_consts.telem_categories import TelemCategoryEnum
from common.event_queue import IEventQueue, PyPubSubEventQueue from common.event_queue import IEventQueue, PyPubSubEventQueue
from common.utils.file_utils import get_binary_io_sha256_hash from common.utils.file_utils import get_binary_io_sha256_hash
from common.version import get_version
from monkey_island.cc import Version
from monkey_island.cc.deployment import Deployment
from monkey_island.cc.repository import ( from monkey_island.cc.repository import (
AgentBinaryRepository, AgentBinaryRepository,
FileAgentConfigurationRepository, FileAgentConfigurationRepository,
@ -49,7 +44,6 @@ from monkey_island.cc.services.telemetry.processing.credentials.credentials_pars
from monkey_island.cc.services.telemetry.processing.processing import ( from monkey_island.cc.services.telemetry.processing.processing import (
TELEMETRY_CATEGORY_TO_PROCESSING_FUNC, TELEMETRY_CATEGORY_TO_PROCESSING_FUNC,
) )
from monkey_island.cc.services.utils.network_utils import get_ip_addresses
from monkey_island.cc.setup.mongo.mongo_setup import MONGO_URL from monkey_island.cc.setup.mongo.mongo_setup import MONGO_URL
from . import AuthenticationService from . import AuthenticationService
@ -58,21 +52,17 @@ from .reporting.report import ReportService
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
AGENT_BINARIES_PATH = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "binaries" AGENT_BINARIES_PATH = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "binaries"
DEPLOYMENT_FILE_PATH = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "deployment.json"
REPOSITORY_KEY_FILE_NAME = "repository_key.bin" REPOSITORY_KEY_FILE_NAME = "repository_key.bin"
def initialize_services(data_dir: Path) -> DIContainer: def initialize_services(container: DIContainer, data_dir: Path):
container = DIContainer()
_register_conventions(container, data_dir) _register_conventions(container, data_dir)
container.register_instance(Deployment, _get_depyloyment_from_file(DEPLOYMENT_FILE_PATH))
container.register_instance(AWSInstance, AWSInstance()) container.register_instance(AWSInstance, AWSInstance())
container.register_instance(MongoClient, MongoClient(MONGO_URL, serverSelectionTimeoutMS=100)) container.register_instance(MongoClient, MongoClient(MONGO_URL, serverSelectionTimeoutMS=100))
container.register_instance( container.register_instance(
ILockableEncryptor, RepositoryEncryptor(data_dir / REPOSITORY_KEY_FILE_NAME) ILockableEncryptor, RepositoryEncryptor(data_dir / REPOSITORY_KEY_FILE_NAME)
) )
container.register_instance(Version, container.resolve(Version))
container.register(Publisher, Publisher) container.register(Publisher, Publisher)
container.register_instance(IEventQueue, container.resolve(PyPubSubEventQueue)) container.register_instance(IEventQueue, container.resolve(PyPubSubEventQueue))
@ -88,11 +78,8 @@ def initialize_services(data_dir: Path) -> DIContainer:
container.resolve(ICredentialsRepository), container.resolve(ICredentialsRepository),
) )
return container
def _register_conventions(container: DIContainer, data_dir: Path): def _register_conventions(container: DIContainer, data_dir: Path):
container.register_convention(Path, "data_dir", data_dir)
container.register_convention( container.register_convention(
AgentConfiguration, "default_agent_configuration", DEFAULT_AGENT_CONFIGURATION AgentConfiguration, "default_agent_configuration", DEFAULT_AGENT_CONFIGURATION
) )
@ -102,8 +89,6 @@ def _register_conventions(container: DIContainer, data_dir: Path):
DEFAULT_RANSOMWARE_AGENT_CONFIGURATION, DEFAULT_RANSOMWARE_AGENT_CONFIGURATION,
) )
container.register_convention(Path, "island_log_file_path", get_log_file_path(data_dir)) container.register_convention(Path, "island_log_file_path", get_log_file_path(data_dir))
container.register_convention(str, "version_number", get_version())
container.register_convention(Sequence[str], "ip_addresses", get_ip_addresses())
def _register_repositories(container: DIContainer, data_dir: Path): def _register_repositories(container: DIContainer, data_dir: Path):
@ -161,22 +146,6 @@ def _log_agent_binary_hashes(agent_binary_repository: IAgentBinaryRepository):
logger.info(f"{os} agent: SHA-256 hash: {binary_sha256_hash}") logger.info(f"{os} agent: SHA-256 hash: {binary_sha256_hash}")
# TODO: The deployment should probably be passed into initialize_services(), but we can rework that
# when we refactor this file.
def _get_depyloyment_from_file(file_path: Path) -> Deployment:
try:
with open(file_path, "r") as deployment_info_file:
deployment_info = json.load(deployment_info_file)
return Deployment[deployment_info["deployment"].upper()]
except KeyError as err:
raise Exception(
f"The deployment file ({file_path}) did not contain the expected data: "
f"missing key {err}"
)
except Exception as err:
raise Exception(f"Failed to fetch the deployment from {file_path}: {err}")
def _register_services(container: DIContainer): def _register_services(container: DIContainer):
container.register_instance(AWSService, container.resolve(AWSService)) container.register_instance(AWSService, container.resolve(AWSService))
container.register_instance(LocalMonkeyRunService, container.resolve(LocalMonkeyRunService)) container.register_instance(LocalMonkeyRunService, container.resolve(LocalMonkeyRunService))