mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Branch was auto-updated.
This commit is contained in:
@@ -163,7 +163,7 @@ jobs:
|
||||
cd bin/automated_detection_testing/ci/detection_testing_batch
|
||||
source .venv/bin/activate
|
||||
|
||||
python3 detection_testing_execution.py run -c prior_config/${{ matrix.manifest_filename}} --splunkbase_username ${{ secrets.SPLUNKBASE_TESTING_USERNAME }} --splunkbase_password ${{ secrets.SPLUNKBASE_TESTING_KEY }}
|
||||
python3 detection_testing_execution.py run -c prior_config/${{ matrix.manifest_filename}}
|
||||
|
||||
|
||||
- name: Upload Test Results Files
|
||||
|
||||
+169
-87
@@ -1,6 +1,7 @@
|
||||
import argparse
|
||||
import copy
|
||||
import csv
|
||||
from ctypes.wintypes import tagRECT
|
||||
import json
|
||||
import os
|
||||
import queue
|
||||
@@ -19,6 +20,8 @@ from tempfile import mkdtemp
|
||||
from timeit import default_timer as timer
|
||||
from typing import Union
|
||||
from urllib.parse import urlparse
|
||||
import signal
|
||||
|
||||
|
||||
import docker
|
||||
import requests
|
||||
@@ -30,7 +33,7 @@ import modules.new_arguments2
|
||||
from modules import (container_manager, new_arguments2,
|
||||
testing_service, validate_args)
|
||||
from modules.github_service import GithubService
|
||||
from modules.validate_args import validate, validate_and_write
|
||||
from modules.validate_args import validate, validate_and_write, ES_APP_NAME
|
||||
|
||||
SPLUNK_CONTAINER_APPS_DIR = "/opt/splunk/etc/apps"
|
||||
index_file_local_path = "indexes.conf.tar"
|
||||
@@ -45,27 +48,60 @@ datamodel_file_container_path = os.path.join(
|
||||
authorizations_file_local_path = "authorize.conf.tar"
|
||||
authorizations_file_container_path = "/opt/splunk/etc/system/local"
|
||||
|
||||
CONTAINER_APP_DIRECTORY = "apps"
|
||||
|
||||
MAX_RECOMMENDED_CONTAINERS_BEFORE_WARNING = 2
|
||||
|
||||
|
||||
def download_file_from_http(url:str, target:str)->None:
|
||||
#Will just overwrite an existing file
|
||||
|
||||
|
||||
|
||||
def download_file_from_http(url:str, destination_file:str, overwrite_file:bool=False)->None:
|
||||
if os.path.exists(destination_file) and overwrite_file is False:
|
||||
print(f"[{destination_file}] already exists...using cached version")
|
||||
return
|
||||
print(f"downloading to [{destination_file}]")
|
||||
file_to_download = requests.get(url, stream=True)
|
||||
with open(target, "wb") as output:
|
||||
with open(destination_file, "wb") as output:
|
||||
for piece in file_to_download.iter_content(chunk_size=(1024*1024)):
|
||||
output.write(piece)
|
||||
|
||||
|
||||
def copy_local_apps_to_directory(apps: dict[str, dict], target_directory) -> None:
|
||||
for key, item in apps.items():
|
||||
def copy_local_apps_to_directory(apps: dict[str, dict], splunkbase_username:tuple[str,None] = None, splunkbase_password:tuple[str,None] = None, mock:bool = False, target_directory:str = "apps") -> str:
|
||||
if mock is True:
|
||||
target_directory = os.path.join("prior_config", target_directory)
|
||||
|
||||
# Remove the apps directory or the prior config directory. If it's just an apps directory, then we don't want
|
||||
#to remove that.
|
||||
shutil.rmtree(target_directory, ignore_errors=True)
|
||||
try:
|
||||
# Make sure the directory exists. If it already did, that's okay. Don't delete anything from it
|
||||
# We want to re-use previously downloaded apps
|
||||
os.makedirs(target_directory, exist_ok = True)
|
||||
|
||||
except Exception as e:
|
||||
raise(Exception(f"Some error occured when trying to make the {target_directory}: [{str(e)}]"))
|
||||
|
||||
|
||||
for key, item in apps.items():
|
||||
|
||||
# These apps are URLs that will be passed. The apps will be downloaded and installed by the container
|
||||
# # Get the file from an http source
|
||||
splunkbase_info = True if ('app_number' in item and item['app_number'] is not None and
|
||||
'app_version' in item and item['app_version'] is not None) else False
|
||||
splunkbase_creds = True if (splunkbase_username is not None and
|
||||
splunkbase_password is not None) else False
|
||||
can_download_from_splunkbase = splunkbase_info and splunkbase_creds
|
||||
|
||||
|
||||
|
||||
#local apps can either have a local_path or an http_path
|
||||
if 'local_path' in item:
|
||||
source_path = os.path.abspath(os.path.expanduser(item['local_path']))
|
||||
base_name = os.path.basename(source_path)
|
||||
dest_path = os.path.join(target_directory, base_name)
|
||||
try:
|
||||
print(f"copying {os.path.relpath(source_path)} to {os.path.relpath(dest_path)}")
|
||||
shutil.copy(source_path, dest_path)
|
||||
item['local_path'] = dest_path
|
||||
except shutil.SameFileError as e:
|
||||
@@ -77,25 +113,34 @@ def copy_local_apps_to_directory(apps: dict[str, dict], target_directory) -> Non
|
||||
source_path, dest_path, str(e)), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# These apps are URLs that will be passed. The apps will be downloaded and installed by the container
|
||||
# # Get the file from an http source
|
||||
# elif 'http_path' in item:
|
||||
# http_path = item['http_path']
|
||||
# try:
|
||||
# url_parse_obj = urlparse(http_path)
|
||||
# path_after_host = url_parse_obj[2].rstrip('/') #removes / at the end, if applicable
|
||||
# base_name = path_after_host.rpartition('/')[-1] #just get the file name
|
||||
# dest_path = os.path.join(target_directory, base_name) #write the whole path
|
||||
# download_file_from_http(http_path, dest_path)
|
||||
# #we need to updat the local path because this is used to copy it into the container later
|
||||
# item['local_path'] = dest_path
|
||||
# except Exception as e:
|
||||
# print("Error trying to download %s @ %s: [%s]. This app is required.\n\tQuitting..."%(key, http_path, str(e)),file=sys.stderr)
|
||||
# sys.exit(1)
|
||||
# else:
|
||||
# print("Error - trying to install a local app that does not have 'local_path' or 'http_path'.\n\tQuitting...")
|
||||
# sys.exit(1)
|
||||
|
||||
elif can_download_from_splunkbase is True:
|
||||
#Don't do anything, this will be downloaded from splunkbase
|
||||
pass
|
||||
elif splunkbase_info is True and splunkbase_creds is False and mock is True:
|
||||
#Don't need to do anything, when this actually runs the apps will be downloaded from Splunkbase
|
||||
#There is another opportunity to provide the creds then
|
||||
pass
|
||||
elif 'http_path' in item and can_download_from_splunkbase is False:
|
||||
http_path = item['http_path']
|
||||
try:
|
||||
url_parse_obj = urlparse(http_path)
|
||||
path_after_host = url_parse_obj[2].rstrip('/') #removes / at the end, if applicable
|
||||
base_name = path_after_host.rpartition('/')[-1] #just get the file name
|
||||
dest_path = os.path.join(target_directory, base_name) #write the whole path
|
||||
download_file_from_http(http_path, dest_path)
|
||||
#we need to update the local path because this is used to copy it into the container later
|
||||
item['local_path'] = dest_path
|
||||
#Remove the HTTP Path, we will use the local_path instead
|
||||
except Exception as e:
|
||||
print("Error trying to download %s @ %s: [%s]. This app is required.\n\tQuitting..."%(key, http_path, str(e)),file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif splunkbase_info is False:
|
||||
print(f"Error - trying to install an app [{key}] that does not have 'local_path', 'http_path', "
|
||||
"or 'app_version' and 'app_number' for installing from Splunkbase.\n\tQuitting...")
|
||||
sys.exit(1)
|
||||
return target_directory
|
||||
|
||||
|
||||
def ensure_security_content(branch: str, commit_hash: Union[str,None], pr_number: Union[int, None], persist_security_content: bool) -> tuple[GithubService, bool]:
|
||||
@@ -183,7 +228,7 @@ def generate_escu_app(persist_security_content: bool = False) -> str:
|
||||
|
||||
else:
|
||||
os.mkdir("slim_packaging")
|
||||
os.mkdir("apps")
|
||||
|
||||
try:
|
||||
SPLUNK_PACKAGING_TOOLKIT_URL = "https://download.splunk.com/misc/packaging-toolkit/splunk-packaging-toolkit-0.9.0.tar.gz"
|
||||
SPLUNK_PACKAGING_TOOLKIT_FILENAME = 'splunk-packaging-toolkit-latest.tar.gz'
|
||||
@@ -216,7 +261,7 @@ def generate_escu_app(persist_security_content: bool = False) -> str:
|
||||
|
||||
ret = subprocess.run("; ".join(commands),
|
||||
shell=True, capture_output=True)
|
||||
if ret.returncode != 0:
|
||||
if ret.returncode != 0:
|
||||
print("Command List:\n%s" % (commands))
|
||||
print("Error generating new ESCU Package.\n\tQuitting and dumping error...\n[%s]" % (
|
||||
ret.stderr.decode('utf-8')), file=sys.stderr)
|
||||
@@ -226,27 +271,10 @@ def generate_escu_app(persist_security_content: bool = False) -> str:
|
||||
return output_file_path_from_root
|
||||
|
||||
|
||||
|
||||
def finish_mock(settings: dict, detections: list[str], output_file_template: str = "prior_config/config_tests_%d.json")->bool:
|
||||
num_containers = settings['num_containers']
|
||||
|
||||
try:
|
||||
# Remove the prior config directory if it exists. If not, continue
|
||||
shutil.rmtree("prior_config", ignore_errors=True)
|
||||
|
||||
# We want to make the prior_config directory and the prior_config/apps directory
|
||||
os.makedirs("prior_config/apps")
|
||||
except FileExistsError as e:
|
||||
print("Directory priorconfig/apps exists, but we just deleted it!\n\tQuitting...", file=sys.stderr)
|
||||
return False
|
||||
except Exception as e:
|
||||
print("Some error occured when trying to make the configs folder: [%s]\n\tQuitting..." % (
|
||||
str(e)), file=sys.stderr)
|
||||
return False
|
||||
|
||||
# Copy the apps to the appropriate local. This will also update
|
||||
# the app paths in settings['local_apps']
|
||||
copy_local_apps_to_directory(settings['local_apps'], "prior_config/apps")
|
||||
|
||||
for output_file_index in range(0, num_containers):
|
||||
fname = output_file_template % (output_file_index)
|
||||
|
||||
@@ -285,9 +313,8 @@ def finish_mock(settings: dict, detections: list[str], output_file_template: str
|
||||
# Make sure that it still validates after all of the changes
|
||||
|
||||
try:
|
||||
with open(fname, 'w') as cfg:
|
||||
validated_settings, b = validate_and_write(
|
||||
mock_settings, cfg)
|
||||
with open(fname, 'w') as outfile:
|
||||
validated_settings, b = validate_and_write(configuration=mock_settings, output_file = outfile, strip_credentials=True)
|
||||
if validated_settings is None:
|
||||
print(
|
||||
"There was an error validating the updated mock settings.\n\tQuitting...", file=sys.stderr)
|
||||
@@ -331,23 +358,40 @@ def main(args: list[str]):
|
||||
|
||||
credentials_needed = False
|
||||
credential_error = False
|
||||
if len(settings['splunkbase_apps']) > 0:
|
||||
credentials_needed = True
|
||||
|
||||
|
||||
if settings['splunkbase_username'] == None and credentials_needed:
|
||||
print("Error - you have listed apps to download from Splunkbase but have "\
|
||||
"not provided --splunkbase_username via the command line or config file.",file=sys.stderr)
|
||||
credential_error = True
|
||||
|
||||
if settings['splunkbase_username'] == None or settings['splunkbase_password'] == None:
|
||||
|
||||
missing_credentials = []
|
||||
if settings['splunkbase_username'] == None:
|
||||
missing_credentials.append("--splunkbase_username")
|
||||
if settings['splunkbase_password'] == None:
|
||||
missing_credentials.append("--splunkbase_password")
|
||||
|
||||
missing_credentials_string = '\n\t'.join(missing_credentials)
|
||||
|
||||
splunkbase_only_apps = []
|
||||
for app,content in settings['apps'].items():
|
||||
if 'local_path' not in content and 'http_path' not in content:
|
||||
splunkbase_only_apps.append(app)
|
||||
if len(splunkbase_only_apps) != 0:
|
||||
print(f"Error - you have attempted to install the following apps: {splunkbase_only_apps}, "
|
||||
"but you have not provided a local_path or an http_path in the config file. Normally, "
|
||||
"we would download these from Splunkbase, but the following credentials are "
|
||||
f"missing:\n\t{missing_credentials_string}\n Please provide them on the command line "
|
||||
"or in the config file.\n\tQuitting...")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"You have listed apps to install but have "\
|
||||
f"not provided\n\t{missing_credentials_string} \nvia the command line or config file. "
|
||||
f"We will download these files from S3 rather than Splunkbase.")
|
||||
else:
|
||||
|
||||
print(f"You have listed apps to install and provided Splunkbase credentials. "\
|
||||
f"These apps will be downloaded and installed from Splunkbase!")
|
||||
|
||||
if settings['splunkbase_password'] == None and credentials_needed:
|
||||
print("Error - you have listed apps to download from Splunkbase but have "\
|
||||
"not provided --splunkbase_password via the command line or config file.",file=sys.stderr)
|
||||
credential_error = True
|
||||
|
||||
if credential_error:
|
||||
print("Please supply the required credentials to continue.\n\tQuitting...",file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
FULL_DOCKER_HUB_CONTAINER_NAME = "splunk/splunk:%s" % settings['container_tag']
|
||||
@@ -405,42 +449,36 @@ def main(args: list[str]):
|
||||
print("***This run will test [%d] detections!***"%(len(all_test_files)))
|
||||
|
||||
|
||||
#Set up the directory that will be used to store the local apps/apps we build
|
||||
local_volume_absolute_path = os.path.abspath(
|
||||
os.path.join(os.getcwd(), "apps"))
|
||||
try:
|
||||
# remove the directory first
|
||||
shutil.rmtree(local_volume_absolute_path, ignore_errors=True)
|
||||
os.mkdir(local_volume_absolute_path)
|
||||
except FileExistsError as e:
|
||||
# Directory already exists, do nothing
|
||||
pass
|
||||
except Exception as e:
|
||||
print("Error creating the apps folder [%s]: [%s]\n\tQuitting..."
|
||||
% (local_volume_absolute_path, str(e)), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
#Add the info about the mount
|
||||
mounts = [{"local_path": local_volume_absolute_path,
|
||||
"container_path": "/tmp/apps", "type": "bind", "read_only": True}]
|
||||
|
||||
|
||||
|
||||
# Check to see if we want to install ESCU and whether it was preeviously generated and we should use that file
|
||||
if 'SPLUNK_ES_CONTENT_UPDATE' in settings['local_apps'] and settings['local_apps']['SPLUNK_ES_CONTENT_UPDATE']['local_path'] is not None:
|
||||
if ES_APP_NAME in settings['apps'] and settings['apps'][ES_APP_NAME]['local_path'] is not None:
|
||||
# Using a pregenerated ESCU, no need to build it
|
||||
pass
|
||||
elif 'SPLUNK_ES_CONTENT_UPDATE' not in settings['local_apps']:
|
||||
print("%s was not found in %s. We assume this is an error and shut down.\n\t"
|
||||
"Quitting..." % ('SPLUNK_ES_CONTENT_UPDATE', "settings['local_apps']"), file=sys.stderr)
|
||||
|
||||
elif ES_APP_NAME not in settings['apps']:
|
||||
print(f"{ES_APP_NAME} was not found in {settings['apps'].keys()}. We assume this is an error and shut down.\n\t"
|
||||
"Quitting...", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Generate the ESCU package from this branch.
|
||||
source_path = generate_escu_app(settings['persist_security_content'])
|
||||
settings['local_apps']['SPLUNK_ES_CONTENT_UPDATE']['local_path'] = source_path
|
||||
settings['apps']['SPLUNK_ES_CONTENT_UPDATE']['local_path'] = source_path
|
||||
|
||||
|
||||
# Copy all the apps, to include ESCU (whether pregenerated or just generated)
|
||||
copy_local_apps_to_directory(
|
||||
settings['local_apps'], local_volume_absolute_path)
|
||||
try:
|
||||
relative_app_path = copy_local_apps_to_directory(settings['apps'],
|
||||
splunkbase_username = settings['splunkbase_username'],
|
||||
splunkbase_password = settings['splunkbase_password'],
|
||||
mock=settings['mock'], target_directory = CONTAINER_APP_DIRECTORY)
|
||||
|
||||
mounts = [{"local_path": os.path.abspath(relative_app_path),
|
||||
"container_path": "/tmp/apps", "type": "bind", "read_only": True}]
|
||||
except Exception as e:
|
||||
print(f"Error occurred when copying apps to app folder: [{str(e)}]\n\tQuitting...", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# If this is a mock run, finish it now
|
||||
@@ -467,13 +505,45 @@ def main(args: list[str]):
|
||||
|
||||
|
||||
|
||||
def shutdown_signal_handler_setup(sig, frame):
|
||||
|
||||
print(f"Signal {sig} received... stopping all [{settings['num_containers']}] containers and shutting down...")
|
||||
shutdown_client = docker.client.from_env()
|
||||
errorCount = 0
|
||||
for container_number in range(settings['num_containers']):
|
||||
container_name = settings['local_base_container_name']%container_number
|
||||
print(f"Shutting down {container_name}...", file=sys.stderr, end='')
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
container = shutdown_client.containers.get(container_name)
|
||||
#Note that stopping does not remove any of the volumes or logs,
|
||||
#so stopping can be useful if we want to debug any container failure
|
||||
container.stop(timeout=10)
|
||||
print("done", file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f"Error trying to shut down {container_name}. It may have already shut down. Stop it youself with 'docker containter stop {container_name}", sys.stderr)
|
||||
errorCount += 1
|
||||
if errorCount == 0:
|
||||
print("All containers shut down successfully", file=sys.stderr)
|
||||
else:
|
||||
print(f"{errorCount} containers may still be running. Find out what is running with:\n\t'docker container ls'\nand shut them down with\n\t'docker container stop CONTAINER_NAME' ", file=sys.stderr)
|
||||
|
||||
print("Quitting...",file=sys.stderr)
|
||||
#We must use os._exit(1) because sys.exit(1) actually generates an exception which can be caught! And then we don't Quit!
|
||||
os._exit(1)
|
||||
|
||||
|
||||
|
||||
|
||||
#Setup requires a different teardown handler than during execution
|
||||
signal.signal(signal.SIGINT, shutdown_signal_handler_setup)
|
||||
|
||||
try:
|
||||
cm = container_manager.ContainerManager(all_test_files,
|
||||
FULL_DOCKER_HUB_CONTAINER_NAME,
|
||||
settings['local_base_container_name'],
|
||||
settings['num_containers'],
|
||||
settings['local_apps'],
|
||||
settings['splunkbase_apps'],
|
||||
settings['apps'],
|
||||
settings['branch'],
|
||||
settings['commit_hash'],
|
||||
reproduce_test_config,
|
||||
@@ -492,6 +562,15 @@ def main(args: list[str]):
|
||||
print("Error - unrecoverable error trying to set up the containers: [%s].\n\tQuitting..."%(str(e)),file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def shutdown_signal_handler_execution(sig, frame):
|
||||
#Set that a container has failed which will gracefully stop the other containers.
|
||||
#This way we get our full cleanup routine, too!
|
||||
print("Got a signal to shut down. Shutting down all containers, please wait...", file=sys.stderr)
|
||||
cm.synchronization_object.containerFailure()
|
||||
|
||||
#Update the signal handler
|
||||
|
||||
signal.signal(signal.SIGINT, shutdown_signal_handler_execution)
|
||||
try:
|
||||
result = cm.run_test()
|
||||
except Exception as e:
|
||||
@@ -508,7 +587,10 @@ def main(args: list[str]):
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("Test Execution Failed - review the logs for more details")
|
||||
sys.exit(1)
|
||||
#Because one or more of the threads could be stuck in a certain setup loop, like
|
||||
#trying to copy files to a containers (which igonores errors), we must os._exit
|
||||
#instead of sys.exit
|
||||
os._exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+38
-25
@@ -1,4 +1,5 @@
|
||||
from collections import OrderedDict
|
||||
from tabnanny import check
|
||||
import docker
|
||||
import datetime
|
||||
import docker.types
|
||||
@@ -25,8 +26,7 @@ class ContainerManager:
|
||||
full_docker_hub_name: str,
|
||||
container_name_template: str,
|
||||
num_containers: int,
|
||||
local_apps: OrderedDict,
|
||||
splunkbase_apps:OrderedDict,
|
||||
apps: OrderedDict,
|
||||
branch:str,
|
||||
commit_hash:str,
|
||||
summarization_reproduce_failure_config:dict,
|
||||
@@ -43,12 +43,15 @@ class ContainerManager:
|
||||
interactive:bool=False
|
||||
|
||||
):
|
||||
#Used to determine whether or not we should wait for container threads to finish when summarizing
|
||||
self.all_tests_completed = False
|
||||
|
||||
self.synchronization_object = test_driver.TestDriver(
|
||||
test_list, num_containers, summarization_reproduce_failure_config)
|
||||
|
||||
self.mounts = self.create_mounts(mounts)
|
||||
self.local_apps = local_apps
|
||||
self.splunkbase_apps = splunkbase_apps
|
||||
self.apps = apps
|
||||
|
||||
|
||||
if container_password is None:
|
||||
self.container_password = self.get_random_password()
|
||||
@@ -93,21 +96,29 @@ class ContainerManager:
|
||||
self.baseline['TEST_FINISH_TIME'] = "TO BE UPDATED"
|
||||
self.baseline['TEST_DURATION'] = "TO BE UPDATED"
|
||||
|
||||
for key in self.local_apps:
|
||||
self.baseline[key] = self.local_apps[key]
|
||||
for key in self.apps:
|
||||
self.baseline[key] = self.apps[key]
|
||||
|
||||
for key in self.splunkbase_apps:
|
||||
self.baseline[key] = self.splunkbase_apps[key]
|
||||
|
||||
|
||||
|
||||
def run_test(self)->bool:
|
||||
self.run_containers()
|
||||
self.run_status_thread()
|
||||
for container in self.containers:
|
||||
container.thread.join()
|
||||
print(container.get_container_summary())
|
||||
print("Waiting for next summary thread printout to finish...")
|
||||
self.run_containers()
|
||||
self.summary_thread.join()
|
||||
|
||||
|
||||
|
||||
|
||||
for container in self.containers:
|
||||
if self.all_tests_completed == True:
|
||||
container.thread.join()
|
||||
elif self.all_tests_completed == False:
|
||||
#For some reason, we stopped early. So don't wait on the child threads to finish. Don't join,
|
||||
#these threads may be stuck in their setup loops. Continue on.
|
||||
pass
|
||||
|
||||
print(container.get_container_summary())
|
||||
print("All containers completed testing!")
|
||||
|
||||
|
||||
@@ -170,8 +181,7 @@ class ContainerManager:
|
||||
self.synchronization_object,
|
||||
full_docker_hub_name,
|
||||
container_name,
|
||||
self.local_apps,
|
||||
self.splunkbase_apps,
|
||||
self.apps,
|
||||
web_port_tuple,
|
||||
management_port_tuple,
|
||||
self.container_password,
|
||||
@@ -219,16 +229,19 @@ class ContainerManager:
|
||||
password = "".join(password_list)
|
||||
return password
|
||||
|
||||
def queue_status_thread(self, status_interval:int=60)->None:
|
||||
def queue_status_thread(self, status_interval:int=60, num_steps:int=10)->None:
|
||||
|
||||
while True:
|
||||
if self.synchronization_object.checkContainerFailure():
|
||||
print("One of the containers has shut down prematurely and generated an exception. Shut down the rest of the containers.")
|
||||
for container in self.containers:
|
||||
container.stopContainer()
|
||||
print("All containers stopped")
|
||||
|
||||
return None
|
||||
#This for loop lets us run the summarize print less often, but check for failure more often
|
||||
for chunk in range(0, status_interval, int(status_interval/num_steps)):
|
||||
if self.synchronization_object.checkContainerFailure():
|
||||
print("One of the containers has shut down prematurely or the test was halted. Ensuring all containers are stopped.")
|
||||
for container in self.containers:
|
||||
container.stopContainer()
|
||||
print("All containers stopped")
|
||||
self.all_tests_completed = False
|
||||
return None
|
||||
time.sleep(status_interval/num_steps)
|
||||
|
||||
at_least_one_container_has_started_running_tests = False
|
||||
for container in self.containers:
|
||||
@@ -237,9 +250,9 @@ class ContainerManager:
|
||||
break
|
||||
if self.synchronization_object.summarize(testing_currently_active = at_least_one_container_has_started_running_tests) == False:
|
||||
#There are no more tests to run, so we can return from this thread
|
||||
|
||||
self.all_tests_completed = True
|
||||
return None
|
||||
time.sleep(status_interval)
|
||||
|
||||
|
||||
def setup_image(self, reuse_images: bool, container_name: str) -> None:
|
||||
client = docker.client.from_env()
|
||||
|
||||
+65
-34
@@ -23,15 +23,14 @@ SPLUNKBASE_URL = "https://splunkbase.splunk.com/app/%d/release/%s/download"
|
||||
SPLUNK_START_ARGS = "--accept-license"
|
||||
|
||||
#Give ten minutes to start - this is probably enough time
|
||||
MAX_CONTAINER_START_TIME_SECONDS = 60*10
|
||||
MAX_CONTAINER_START_TIME_SECONDS = 60*20
|
||||
class SplunkContainer:
|
||||
def __init__(
|
||||
self,
|
||||
synchronization_object: test_driver.TestDriver,
|
||||
full_docker_hub_path,
|
||||
container_name: str,
|
||||
local_apps: OrderedDict,
|
||||
splunkbase_apps: OrderedDict,
|
||||
apps: OrderedDict,
|
||||
web_port_tuple: tuple[str, int],
|
||||
management_port_tuple: tuple[str, int],
|
||||
container_password: str,
|
||||
@@ -49,15 +48,15 @@ class SplunkContainer:
|
||||
self.client = docker.client.from_env()
|
||||
self.full_docker_hub_path = full_docker_hub_path
|
||||
self.container_password = container_password
|
||||
self.local_apps = local_apps
|
||||
self.splunkbase_apps = splunkbase_apps
|
||||
|
||||
self.apps = apps
|
||||
|
||||
self.files_to_copy_to_container = files_to_copy_to_container
|
||||
self.splunk_ip = splunk_ip
|
||||
self.container_name = container_name
|
||||
self.mounts = mounts
|
||||
self.environment = self.make_environment(
|
||||
local_apps, splunkbase_apps, container_password, splunkbase_username, splunkbase_password
|
||||
apps, container_password, splunkbase_username, splunkbase_password
|
||||
)
|
||||
self.ports = self.make_ports(web_port_tuple, management_port_tuple)
|
||||
self.web_port = web_port_tuple[1]
|
||||
@@ -72,50 +71,56 @@ class SplunkContainer:
|
||||
self.num_tests_completed = 0
|
||||
|
||||
|
||||
|
||||
def prepare_apps_path(
|
||||
self,
|
||||
local_apps: OrderedDict,
|
||||
splunkbase_apps: OrderedDict,
|
||||
apps: OrderedDict,
|
||||
splunkbase_username: Union[str, None] = None,
|
||||
splunkbase_password: Union[str, None] = None,
|
||||
) -> tuple[str, bool]:
|
||||
apps_to_install = []
|
||||
|
||||
#We don't require credentials unless we install at least one splunkbase app
|
||||
require_credentials = False
|
||||
|
||||
for app_name, app_info in self.local_apps.items():
|
||||
|
||||
if 'local_path' in app_info:
|
||||
#If the username and password are supplied, then we will use splunkbase...
|
||||
#assuming that the app_name and app_number are supplied. Note that if a
|
||||
#local_path is supplied, then it should override this option!
|
||||
if splunkbase_username is not None and splunkbase_password is not None:
|
||||
use_splunkbase = True
|
||||
else:
|
||||
use_splunkbase = False
|
||||
|
||||
for app_name, app_info in self.apps.items():
|
||||
if use_splunkbase is True and 'local_path' not in app_info:
|
||||
target = SPLUNKBASE_URL % (app_info["app_number"], app_info["app_version"])
|
||||
apps_to_install.append(target)
|
||||
#We will require credentials since we are installing at least one splunkbase app
|
||||
require_credentials = True
|
||||
#Some paths may have a local_path and an HTTP path defined. Default to the local_path first,
|
||||
#mostly because we may have copied it before into the cache to speed up start time.
|
||||
elif 'local_path' in app_info:
|
||||
app_file_name = os.path.basename(app_info['local_path'])
|
||||
app_file_container_path = os.path.join("/tmp/apps", app_file_name)
|
||||
apps_to_install.append(app_file_container_path)
|
||||
apps_to_install.append(app_file_container_path)
|
||||
elif 'http_path' in app_info:
|
||||
apps_to_install.append(app_info['http_path'])
|
||||
|
||||
else:
|
||||
print("Error, the app %s: %s has no http_path or local_path.\n\tQuitting..."%(app_name,app_info), file=sys.stderr)
|
||||
if use_splunkbase is True:
|
||||
print("Error, the app %s: %s could not be installed from Splunkbase because "
|
||||
"--splunkbase_username and.or --splunkbase_password were not provided."
|
||||
"\n\tQuitting..."%(app_name,app_info), file=sys.stderr)
|
||||
else:
|
||||
print("Error, the app %s: %s has no http_path or local_path.\n\tQuitting..."%(app_name,app_info), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
for app_name, app_info in self.splunkbase_apps.items():
|
||||
|
||||
if splunkbase_username is None or splunkbase_password is None:
|
||||
raise Exception(
|
||||
"Error: Requested app from Splunkbase but Splunkbase username and/or password were not supplied."
|
||||
)
|
||||
target = SPLUNKBASE_URL % (
|
||||
app_info["app_number"], app_info["app_version"])
|
||||
apps_to_install.append(target)
|
||||
require_credentials = True
|
||||
# elif app["location"] == "local":
|
||||
# apps_to_install.append(app["container_path"])
|
||||
|
||||
#for printing out all the app paths we will install
|
||||
#for num, name in zip(range(len(apps_to_install)),apps_to_install):
|
||||
# print("%d: %s"%(num,name))
|
||||
return ",".join(apps_to_install), require_credentials
|
||||
|
||||
def make_environment(
|
||||
self,
|
||||
local_apps: OrderedDict,
|
||||
splunkbase_apps: OrderedDict,
|
||||
apps: OrderedDict,
|
||||
container_password: str,
|
||||
splunkbase_username: Union[str, None] = None,
|
||||
splunkbase_password: Union[str, None] = None,
|
||||
@@ -124,7 +129,7 @@ class SplunkContainer:
|
||||
env["SPLUNK_START_ARGS"] = SPLUNK_START_ARGS
|
||||
env["SPLUNK_PASSWORD"] = container_password
|
||||
splunk_apps_url, require_credentials = self.prepare_apps_path(
|
||||
local_apps, splunkbase_apps, splunkbase_username, splunkbase_password
|
||||
apps, splunkbase_username, splunkbase_password
|
||||
)
|
||||
|
||||
if require_credentials:
|
||||
@@ -314,10 +319,36 @@ class SplunkContainer:
|
||||
time.sleep(seconds_between_attempts)
|
||||
|
||||
|
||||
@wrapt_timeout_decorator.timeout(MAX_CONTAINER_START_TIME_SECONDS, timeout_exception=RuntimeError)
|
||||
#@wrapt_timeout_decorator.timeout(MAX_CONTAINER_START_TIME_SECONDS, timeout_exception=RuntimeError)
|
||||
def setup_container(self):
|
||||
|
||||
|
||||
self.container.start()
|
||||
|
||||
|
||||
# def shutdown_signal_handler(sig, frame):
|
||||
# shutdown_client = docker.client.from_env()
|
||||
# errorCount = 0
|
||||
|
||||
# print(f"Shutting down {self.container_name}...", file=sys.stderr)
|
||||
# try:
|
||||
# container = shutdown_client.containers.get(self.container_name)
|
||||
# #Note that stopping does not remove any of the volumes or logs,
|
||||
# #so stopping can be useful if we want to debug any container failure
|
||||
# container.stop(timeout=10)
|
||||
# print(f"{self.container_name} shut down successfully", file=sys.stderr)
|
||||
# except Exception as e:
|
||||
# print(f"Error trying to shut down {self.container_name}. It may have already shut down. Stop it youself with 'docker containter stop {self.container_name}", sys.stderr)
|
||||
|
||||
|
||||
# #We must use os._exit(1) because sys.exit(1) actually generates an exception which can be caught! And then we don't Quit!
|
||||
# import os
|
||||
# os._exit(1)
|
||||
|
||||
|
||||
|
||||
# import signal
|
||||
# signal.signal(signal.SIGINT, shutdown_signal_handler)
|
||||
|
||||
# By default, first copy the index file then the datamodel file
|
||||
for file_description, file_dict in self.files_to_copy_to_container.items():
|
||||
self.extract_tar_file_to_container(
|
||||
@@ -419,7 +450,7 @@ class SplunkContainer:
|
||||
% (detection_to_test, str(e))
|
||||
)
|
||||
|
||||
traceback.print_exc()
|
||||
#traceback.print_exc()
|
||||
#import pdb
|
||||
#pdb.set_trace()
|
||||
# Fill in all the "Empty" fields with default values. Otherwise, we will not be able to
|
||||
|
||||
@@ -235,7 +235,7 @@ class TestDriver:
|
||||
|
||||
|
||||
if self.checkContainerFailure():
|
||||
print("One or more containers crashed, so testing did not complete successfully. We wrote out all the results that we could")
|
||||
print("One or more containers crashed or the test was HALTED early, so testing did not complete successfully. We wrote out all the results that we could")
|
||||
return False
|
||||
else:
|
||||
return success
|
||||
@@ -269,16 +269,7 @@ class TestDriver:
|
||||
|
||||
|
||||
def summarize(self,testing_currently_active:bool=False)->bool:
|
||||
|
||||
if self.checkContainerFailure() == True:
|
||||
print("Error running containers... shutting down", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
self.lock.acquire()
|
||||
|
||||
try:
|
||||
|
||||
#Get a summary of some system stats
|
||||
|
||||
+70
-182
@@ -8,7 +8,7 @@ from typing import Union
|
||||
|
||||
|
||||
# If we want, we can easily add a description field to any of the objects here!
|
||||
|
||||
ES_APP_NAME = "SPLUNK_ES_CONTENT_UPDATE"
|
||||
setup_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -50,7 +50,7 @@ setup_schema = {
|
||||
},
|
||||
|
||||
|
||||
"local_apps": {
|
||||
"apps": {
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"patternProperties": {
|
||||
@@ -59,131 +59,113 @@ setup_schema = {
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"app_number": {
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
"type": ["integer","null"]
|
||||
},
|
||||
"app_version": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
"type": ["string","null"]
|
||||
},
|
||||
"local_path": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
"type": ["string","null"]
|
||||
},
|
||||
"http_path": {
|
||||
"type": [
|
||||
"string"
|
||||
]
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
"anyOf": [
|
||||
{"required": ["local_path"]},
|
||||
{"required": ["http_path"]}
|
||||
{"required": ["http_path"] },
|
||||
{"required": ["app_number", "app_version"] },
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"SPLUNK_ES_CONTENT_UPDATE": {
|
||||
ES_APP_NAME : {
|
||||
"app_number": 3449,
|
||||
"app_version": None,
|
||||
"local_path": None
|
||||
},
|
||||
#The default apps below were taken from the attack_range loadout: https://github.com/splunk/attack_range/blob/develop/attack_range.conf.template
|
||||
"SPLUNK_WINDOWS_TA": {
|
||||
"app_number": 0,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-windows_812.tgz"
|
||||
"SPLUNK_ADD_ON_FOR_MICROSOFT_WINDOWS": {
|
||||
"app_number": 742,
|
||||
"app_version": "8.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-microsoft-windows_840.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON_OLD": {
|
||||
"app_number": 1,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-sysmon_1062.tgz"
|
||||
"ADD_ON_FOR_LINUX_SYSMON": {
|
||||
"app_number": 6176,
|
||||
"app_version": "1.0.4",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/add-on-for-linux-sysmon_104.tgz"
|
||||
},
|
||||
"SPLUNK_SYSMON_LINUX_TA_PATCHED": {
|
||||
"app_number": 2,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/add-on-for-linux-sysmon_103_PATCHED.tgz"
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON": {
|
||||
"app_number": 5709,
|
||||
"app_version": "2.0.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-sysmon_200.tgz"
|
||||
},
|
||||
"SPLUNK_CIM_APP": {
|
||||
"app_number": 3,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-common-information-model-cim_4200.tgz"
|
||||
"SPLUNK_COMMON_INFORMATION_MODEL": {
|
||||
"app_number": 1621,
|
||||
"app_version": "5.0.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-common-information-model-cim_500.tgz"
|
||||
},
|
||||
"SPLUNK_AWS_TA": {
|
||||
"app_number": 4,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-amazon-web-services_510.tgz"
|
||||
#Note - end of life on July 15, 2022 - https://splunkbase.splunk.com/app/1274/
|
||||
"SPLUNK_APP_FOR_AWS": {
|
||||
"app_number": 1274,
|
||||
"app_version": "6.0.3",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-app-for-aws_603.tgz"
|
||||
},
|
||||
"SPLUNK_PYTHON_APP": {
|
||||
"app_number": 5,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/python-for-scientific-computing-for-linux-64-bit_202.tgz"
|
||||
"PYTHON_FOR_SCIENTIFIC_COMPUTING_FOR_LINUX_64_BIT": {
|
||||
"app_number": 2882,
|
||||
"app_version": "3.0.2",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/python-for-scientific-computing-for-linux-64-bit_302.tgz"
|
||||
},
|
||||
"SPLUNK_ASX_APP": {
|
||||
"app_number": 17,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/Splunk_ASX-latest.tar.gz"
|
||||
"SPLUNK_MACHINE_LEARNING_TOOLKIT": {
|
||||
"app_number": 2890,
|
||||
"app_version": "5.3.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-machine-learning-toolkit_531.tgz"
|
||||
},
|
||||
"SPLUNK_MLTK_APP": {
|
||||
"app_number": 6,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-machine-learning-toolkit_521.tgz"
|
||||
},
|
||||
"SPLUNK_STREAM_APP": {
|
||||
"app_number": 7,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-app-for-stream_730.tgz"
|
||||
"SPLUNK_APP_FOR_STREAM": {
|
||||
"app_number": 1809,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-app-for-stream_801.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_WIRE_DATA": {
|
||||
"app_number": 8,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-stream-wire-data_730.tgz"
|
||||
"app_number": 5234,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-stream-wire-data_801.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_FORWARDERS": {
|
||||
"app_number": 9,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-stream-forwarders_730.tgz"
|
||||
"app_number": 5238,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-stream-forwarders_801.tgz"
|
||||
},
|
||||
"SPLUNK_SECURITY_ESSENTIALS": {
|
||||
"app_number": 10,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-security-essentials_333.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_ZEEK_AKA_BRO": {
|
||||
"app_number": 11,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-zeek-aka-bro_400.tgz"
|
||||
"app_number": 3435,
|
||||
"app_version": "3.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-security-essentials_340.tgz"
|
||||
},
|
||||
|
||||
"SPLUNK_ADD_ON_FOR_AMAZON_KINESIS_FIREHOSE": {
|
||||
"app_number": 12,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-amazon-kinesis-firehose_131r7d1d093.tgz"
|
||||
"app_number": 3719,
|
||||
"app_version": "1.3.2",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-amazon-kinesis-firehose_132.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_MICROSOFT_OFFICE_365": {
|
||||
"app_number": 13,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-office-365_202.tgz"
|
||||
"app_number": 4055,
|
||||
"app_version": "2.2.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-microsoft-office-365_220.tgz"
|
||||
},
|
||||
"SPLUNK_LINUX_TA": {
|
||||
"app_number": 14,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-unix-and-linux_820.tgz"
|
||||
"SPLUNK_ADD_ON_FOR_UNIX_AND_LINUX": {
|
||||
"app_number": 833,
|
||||
"app_version": "8.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-unix-and-linux_840.tgz"
|
||||
},
|
||||
"SPLUNK_NGINX_TA": {
|
||||
"app_number": 15,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-nginx_310.tgz"
|
||||
"SPLUNK_ADD_ON_FOR_NGINX": {
|
||||
"app_number": 3258,
|
||||
"app_version": "3.1.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-nginx_310.tgz"
|
||||
},
|
||||
"SPLUNK_TA_FOR_ZEEK": {
|
||||
"app_number": 16,
|
||||
"app_version": None,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/ta-for-zeek_105.tgz"
|
||||
"app_number": 5466,
|
||||
"app_version": "1.0.5",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/ta-for-zeek_105.tgz"
|
||||
},
|
||||
|
||||
}
|
||||
@@ -226,100 +208,6 @@ setup_schema = {
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
"splunkbase_apps": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"app_number": {
|
||||
"type": "integer"
|
||||
},
|
||||
"app_version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"default": {
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON": {
|
||||
"app_number": 5709,
|
||||
"app_version": "1.0.1"
|
||||
}
|
||||
},
|
||||
|
||||
# "default": {
|
||||
# "ADD-ON_FOR_LINUX_SYSMON": {
|
||||
# "app_number": 6176,
|
||||
# "app_version": "1.0.3"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_AMAZON_WEB_SERVICES": {
|
||||
# "app_number": 1876,
|
||||
# "app_version": "5.2.1"
|
||||
# },
|
||||
|
||||
# "SPLUNK_ADD_ON_FOR_MICROSOFT_OFFICE_365":
|
||||
# {
|
||||
# "app_number": 4055,
|
||||
# "app_version": "2.2.0"
|
||||
# },
|
||||
|
||||
# "SPLUNK_ADD_ON_FOR_AMAZON_KINESIS_FIREHOSE": {
|
||||
# "app_number": 3719,
|
||||
# "app_version": "1.3.2"
|
||||
# },
|
||||
|
||||
# "SPLUNK_ANALYTIC_STORY_EXECUTION_APP": {
|
||||
# "app_number": 4971,
|
||||
# "app_version": "2.0.3"
|
||||
# },
|
||||
|
||||
# "PYTHON_FOR_SCIENTIC_COMPUTING_LINUX_64_BIT": {
|
||||
# "app_number": 2882,
|
||||
# "app_version": "3.0.1"
|
||||
# },
|
||||
|
||||
# "SPLUNK_MACHINE_LEARNING_TOOLKIT": {
|
||||
# "app_number": 2890,
|
||||
# "app_version": "5.3.0"
|
||||
# },
|
||||
|
||||
# "SPLUNK_APP_FOR_STREAM": {
|
||||
# "app_number": 1809,
|
||||
# "app_version": "8.0.1"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_STREAM_WIRE_DATA": {
|
||||
# "app_number": 5234,
|
||||
# "app_version": "8.0.1"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_STREAM_FORWARDERS": {
|
||||
# "app_number": 5238,
|
||||
# "app_version": "8.0.1"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_ZEEK_AKA_BRO": {
|
||||
# "app_number": 1617,
|
||||
# "app_version": "4.0.0"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_UNIX_AND_LINUX": {
|
||||
# "app_number": 833,
|
||||
# "app_version": "8.4.0"
|
||||
# },
|
||||
# "SPLUNK_ADD_ON_FOR_SYSMON": {
|
||||
# "app_number": 5709,
|
||||
# "app_version": "1.0.1"
|
||||
# },
|
||||
# # According to https://docs.splunk.com/Documentation/ES/6.6.2/Install/Datamodels, these are included in ES. Don't install separately.
|
||||
# "SPLUNK_COMMON_INFORMATION_MODEL": {
|
||||
# "app_number": 1621,
|
||||
# "app_version": "5.0.0"
|
||||
# }
|
||||
# }
|
||||
},
|
||||
|
||||
"splunkbase_username": {
|
||||
"type": ["string", "null"],
|
||||
"default": None
|
||||
|
||||
+95
-111
@@ -1,113 +1,103 @@
|
||||
{
|
||||
"apps": {
|
||||
"ADD_ON_FOR_LINUX_SYSMON": {
|
||||
"app_number": 6176,
|
||||
"app_version": "1.0.4",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/add-on-for-linux-sysmon_104.tgz"
|
||||
},
|
||||
"PYTHON_FOR_SCIENTIFIC_COMPUTING_FOR_LINUX_64_BIT": {
|
||||
"app_number": 2882,
|
||||
"app_version": "3.0.2",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/python-for-scientific-computing-for-linux-64-bit_302.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_AMAZON_KINESIS_FIREHOSE": {
|
||||
"app_number": 3719,
|
||||
"app_version": "1.3.2",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-amazon-kinesis-firehose_132.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_MICROSOFT_OFFICE_365": {
|
||||
"app_number": 4055,
|
||||
"app_version": "2.2.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-microsoft-office-365_220.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_MICROSOFT_WINDOWS": {
|
||||
"app_number": 742,
|
||||
"app_version": "8.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-microsoft-windows_840.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_NGINX": {
|
||||
"app_number": 3258,
|
||||
"app_version": "3.1.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-nginx_310.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_FORWARDERS": {
|
||||
"app_number": 5238,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-stream-forwarders_801.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_WIRE_DATA": {
|
||||
"app_number": 5234,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-stream-wire-data_801.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON": {
|
||||
"app_number": 5709,
|
||||
"app_version": "2.0.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-sysmon_200.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_UNIX_AND_LINUX": {
|
||||
"app_number": 833,
|
||||
"app_version": "8.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-add-on-for-unix-and-linux_840.tgz"
|
||||
},
|
||||
"SPLUNK_APP_FOR_AWS": {
|
||||
"app_number": 1274,
|
||||
"app_version": "6.0.3",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-app-for-aws_603.tgz"
|
||||
},
|
||||
"SPLUNK_APP_FOR_STREAM": {
|
||||
"app_number": 1809,
|
||||
"app_version": "8.0.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-app-for-stream_801.tgz"
|
||||
},
|
||||
"SPLUNK_COMMON_INFORMATION_MODEL": {
|
||||
"app_number": 1621,
|
||||
"app_version": "5.0.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-common-information-model-cim_500.tgz"
|
||||
},
|
||||
"SPLUNK_ES_CONTENT_UPDATE": {
|
||||
"app_number": 3449,
|
||||
"app_version": null,
|
||||
"local_path": null
|
||||
},
|
||||
"SPLUNK_MACHINE_LEARNING_TOOLKIT": {
|
||||
"app_number": 2890,
|
||||
"app_version": "5.3.1",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-machine-learning-toolkit_531.tgz"
|
||||
},
|
||||
"SPLUNK_SECURITY_ESSENTIALS": {
|
||||
"app_number": 3435,
|
||||
"app_version": "3.4.0",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/splunk-security-essentials_340.tgz"
|
||||
},
|
||||
"SPLUNK_TA_FOR_ZEEK": {
|
||||
"app_number": 5466,
|
||||
"app_version": "1.0.5",
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/Latest/ta-for-zeek_105.tgz"
|
||||
}
|
||||
},
|
||||
"branch": "BRANCH_DOES_NOT_EXIST_USE_CLI_ARGUMENT",
|
||||
"commit_hash": null,
|
||||
"container_tag": "latest",
|
||||
"detections_file": null,
|
||||
"detections_list": null,
|
||||
"folders": [
|
||||
"endpoint",
|
||||
"cloud",
|
||||
"network",
|
||||
"web"
|
||||
"endpoint",
|
||||
"cloud",
|
||||
"network",
|
||||
"web"
|
||||
],
|
||||
"interactive": false,
|
||||
"local_apps": {
|
||||
"SPLUNK_ADD_ON_FOR_AMAZON_KINESIS_FIREHOSE": {
|
||||
"app_number": 12,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-amazon-kinesis-firehose_131r7d1d093.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_MICROSOFT_OFFICE_365": {
|
||||
"app_number": 13,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-office-365_202.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_FORWARDERS": {
|
||||
"app_number": 9,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-stream-forwarders_730.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_STREAM_WIRE_DATA": {
|
||||
"app_number": 8,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-stream-wire-data_730.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON_OLD": {
|
||||
"app_number": 1,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-sysmon_1062.tgz"
|
||||
},
|
||||
"SPLUNK_ADD_ON_FOR_ZEEK_AKA_BRO": {
|
||||
"app_number": 11,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-zeek-aka-bro_400.tgz"
|
||||
},
|
||||
"SPLUNK_ASX_APP": {
|
||||
"app_number": 17,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/Splunk_ASX-latest.tar.gz"
|
||||
},
|
||||
"SPLUNK_AWS_TA": {
|
||||
"app_number": 4,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-amazon-web-services_510.tgz"
|
||||
},
|
||||
"SPLUNK_CIM_APP": {
|
||||
"app_number": 3,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-common-information-model-cim_4200.tgz"
|
||||
},
|
||||
"SPLUNK_ES_CONTENT_UPDATE": {
|
||||
"app_number": 3449,
|
||||
"app_version": null,
|
||||
"local_path": null
|
||||
},
|
||||
"SPLUNK_LINUX_TA": {
|
||||
"app_number": 14,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-unix-and-linux_820.tgz"
|
||||
},
|
||||
"SPLUNK_MLTK_APP": {
|
||||
"app_number": 6,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/splunk-machine-learning-toolkit_531.tgz"
|
||||
},
|
||||
"SPLUNK_NGINX_TA": {
|
||||
"app_number": 15,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-nginx_310.tgz"
|
||||
},
|
||||
"SPLUNK_PYTHON_APP": {
|
||||
"app_number": 5,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3.us-west-2.amazonaws.com/python-for-scientific-computing-for-linux-64-bit_302.tgz"
|
||||
},
|
||||
"SPLUNK_SECURITY_ESSENTIALS": {
|
||||
"app_number": 10,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-security-essentials_333.tgz"
|
||||
},
|
||||
"SPLUNK_STREAM_APP": {
|
||||
"app_number": 7,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-app-for-stream_730.tgz"
|
||||
},
|
||||
"SPLUNK_SYSMON_LINUX_TA_PATCHED": {
|
||||
"app_number": 2,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/add-on-for-linux-sysmon_103_PATCHED.tgz"
|
||||
},
|
||||
"SPLUNK_TA_FOR_ZEEK": {
|
||||
"app_number": 16,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/ta-for-zeek_105.tgz"
|
||||
},
|
||||
"SPLUNK_WINDOWS_TA": {
|
||||
"app_number": 0,
|
||||
"app_version": null,
|
||||
"http_path": "https://attack-range-appbinaries.s3-us-west-2.amazonaws.com/splunk-add-on-for-microsoft-windows_812.tgz"
|
||||
}
|
||||
},
|
||||
"local_base_container_name": "splunk_test_%d",
|
||||
"mock": false,
|
||||
"mode": "changes",
|
||||
@@ -119,17 +109,11 @@
|
||||
"show_splunk_app_password": false,
|
||||
"splunk_app_password": null,
|
||||
"splunk_container_apps_directory": "/opt/splunk/etc/apps",
|
||||
"splunkbase_apps": {
|
||||
"SPLUNK_ADD_ON_FOR_SYSMON": {
|
||||
"app_number": 5709,
|
||||
"app_version": "1.0.1"
|
||||
}
|
||||
},
|
||||
"splunkbase_password": null,
|
||||
"splunkbase_username": null,
|
||||
"types": [
|
||||
"Anomaly",
|
||||
"Hunting",
|
||||
"TTP"
|
||||
"Anomaly",
|
||||
"Hunting",
|
||||
"TTP"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user