mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-06 09:12:45 +01:00
Compare commits
212 Commits
2.4/main
...
c4a70b540e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4a70b540e | ||
|
|
bef85772e3 | ||
|
|
a6b19c4a6c | ||
|
|
44f5e6659b | ||
|
|
3f9a9b7019 | ||
|
|
b7ad985c7a | ||
|
|
dba087ae25 | ||
|
|
bbc4b1b502 | ||
|
|
9304513ce8 | ||
|
|
0b127582cb | ||
|
|
6e9b8791c8 | ||
|
|
ef87ad77c3 | ||
|
|
8477420911 | ||
|
|
f5741e318f | ||
|
|
e010b5680a | ||
|
|
8620d3987e | ||
|
|
30487a54c1 | ||
|
|
f15a39c153 | ||
|
|
aed27fa111 | ||
|
|
822c411e83 | ||
|
|
41b3ac7554 | ||
|
|
23575fdf6c | ||
|
|
52f70dc49a | ||
|
|
79c9749ff7 | ||
|
|
8d2701e143 | ||
|
|
877444ac29 | ||
|
|
b0d9426f1b | ||
|
|
18accae47e | ||
|
|
55e3a2c6b6 | ||
|
|
ef092e2893 | ||
|
|
89eb95c077 | ||
|
|
e871ec358e | ||
|
|
271a2f74ad | ||
|
|
d6bd951c37 | ||
|
|
8abd4c9c78 | ||
|
|
45a8c0acd1 | ||
|
|
c372cd533d | ||
|
|
999f83ce57 | ||
|
|
6fbed2dd9f | ||
|
|
875de88cb4 | ||
|
|
63bb44886e | ||
|
|
bda83a47a2 | ||
|
|
e96cfd35f7 | ||
|
|
65c96b2edf | ||
|
|
87477ae4f6 | ||
|
|
89a9106d79 | ||
|
|
1284150382 | ||
|
|
edf3c9464f | ||
|
|
4bb0a7c9d9 | ||
|
|
ced3af818c | ||
|
|
cc8fb96047 | ||
|
|
3339b50daf | ||
|
|
415ea07a4f | ||
|
|
b80ec95fa8 | ||
|
|
99cb51482f | ||
|
|
90638f7a43 | ||
|
|
1fb00c8eb6 | ||
|
|
4490ea7635 | ||
|
|
bce7a20d8b | ||
|
|
9c06713f32 | ||
|
|
23da0d4ba0 | ||
|
|
d5f2cfb354 | ||
|
|
fb5ad4193d | ||
|
|
1f5f283c06 | ||
|
|
cf048030c4 | ||
|
|
2d716b44a8 | ||
|
|
d70d652310 | ||
|
|
c5db7c8752 | ||
|
|
6f42ff3442 | ||
|
|
433dab7376 | ||
|
|
97c1a46013 | ||
|
|
fbe97221bb | ||
|
|
841ce6b6ec | ||
|
|
dd0b4c3820 | ||
|
|
b52dd53e29 | ||
|
|
a155f45036 | ||
|
|
b407c68d88 | ||
|
|
5b6a7035af | ||
|
|
12d490ad4a | ||
|
|
76cbd18d2c | ||
|
|
148ef7ef21 | ||
|
|
1b55642c86 | ||
|
|
af7f7d0728 | ||
|
|
a7337c95e1 | ||
|
|
3f7c3326ea | ||
|
|
bf41de8c14 | ||
|
|
de4424fab0 | ||
|
|
136a829509 | ||
|
|
bcec999be4 | ||
|
|
7c73b4713f | ||
|
|
45b4b1d963 | ||
|
|
fcfd74ec1e | ||
|
|
68b0cd7549 | ||
|
|
715d801ce8 | ||
|
|
4a810696e7 | ||
|
|
6b525a2c21 | ||
|
|
a5d8385f07 | ||
|
|
211bf7e77b | ||
|
|
1542b74133 | ||
|
|
431e5abf89 | ||
|
|
4314c79f85 | ||
|
|
da9717bc79 | ||
|
|
f047677d8a | ||
|
|
045cf7866c | ||
|
|
431e0b0780 | ||
|
|
e782266caa | ||
|
|
a4666b2c08 | ||
|
|
dcc3206e51 | ||
|
|
8358b6ea6f | ||
|
|
d1a66a91c6 | ||
|
|
7fdcb92614 | ||
|
|
cec1890b6b | ||
|
|
b2606b6094 | ||
|
|
b1b66045ea | ||
|
|
33b22bf2e4 | ||
|
|
3a38886345 | ||
|
|
7be70faab6 | ||
|
|
2729fdbea6 | ||
|
|
bfd08d1d2e | ||
|
|
37b3fd9b7b | ||
|
|
573dded921 | ||
|
|
fed75c7b39 | ||
|
|
3427df2a54 | ||
|
|
be11c718f6 | ||
|
|
235dfd78f1 | ||
|
|
7c8b9b4374 | ||
|
|
81d7c313af | ||
|
|
9a6ff75793 | ||
|
|
1f24796eba | ||
|
|
7762faf075 | ||
|
|
80fbb31372 | ||
|
|
7c45db2295 | ||
|
|
0545e1d33b | ||
|
|
55bbbdb58d | ||
|
|
3a8a6bf5ff | ||
|
|
13789bc56f | ||
|
|
11518f6eea | ||
|
|
08147e27b0 | ||
|
|
c9153617be | ||
|
|
245ceb2d49 | ||
|
|
4c65975907 | ||
|
|
dfef7036ce | ||
|
|
44594ba726 | ||
|
|
1876c4d9df | ||
|
|
a2ff66b5d0 | ||
|
|
e3972dc5af | ||
|
|
18c0f197b2 | ||
|
|
5b371c220c | ||
|
|
78c193f0a2 | ||
|
|
274295bc97 | ||
|
|
6c7ef622c1 | ||
|
|
da1cac0d53 | ||
|
|
a84df14137 | ||
|
|
4a49f9d004 | ||
|
|
1eb4b5379a | ||
|
|
35c7fc06d7 | ||
|
|
b69d453a68 | ||
|
|
2f6fb717c1 | ||
|
|
b7e1989d45 | ||
|
|
202b03b32b | ||
|
|
1aa871ec94 | ||
|
|
4ffbb0bbd9 | ||
|
|
f859fe6517 | ||
|
|
021b425b8b | ||
|
|
d95122ca01 | ||
|
|
81d3c7351b | ||
|
|
ccb8ffd6eb | ||
|
|
5a8ea57a1b | ||
|
|
60228ec6e6 | ||
|
|
574703e551 | ||
|
|
fa154f1a8f | ||
|
|
635545630b | ||
|
|
df8afda999 | ||
|
|
f80b090c93 | ||
|
|
806173f7e3 | ||
|
|
2f6c1b82a6 | ||
|
|
b8c2808abe | ||
|
|
9027e4e065 | ||
|
|
8ca5276a0e | ||
|
|
ee45a5524d | ||
|
|
70d4223a75 | ||
|
|
7ab2840381 | ||
|
|
78c951cb70 | ||
|
|
a0a3a80151 | ||
|
|
3ecffd5588 | ||
|
|
8ea66bb0e9 | ||
|
|
9359fbbad6 | ||
|
|
1949be90c2 | ||
|
|
30970acfaf | ||
|
|
6d12a8bfa1 | ||
|
|
2fb41c8d65 | ||
|
|
835b2609b6 | ||
|
|
10ae53f108 | ||
|
|
68bfceb727 | ||
|
|
f348c7168f | ||
|
|
627d9bf45d | ||
|
|
2aee8ab511 | ||
|
|
92be8df95d | ||
|
|
b1acbf3114 | ||
|
|
8043e09ec1 | ||
|
|
25c746bb14 | ||
|
|
a91e8b26f6 | ||
|
|
e826ea5d04 | ||
|
|
23a9780ebb | ||
|
|
9cb8ebbaa7 | ||
|
|
ded520c2c1 | ||
|
|
a77157391c | ||
|
|
03892bad5e | ||
|
|
77fef02116 | ||
|
|
f3328c41fb | ||
|
|
23ae259c82 | ||
|
|
45f25ca62d |
1
.github/DISCUSSION_TEMPLATE/2-4.yml
vendored
1
.github/DISCUSSION_TEMPLATE/2-4.yml
vendored
@@ -32,6 +32,7 @@ body:
|
|||||||
- 2.4.170
|
- 2.4.170
|
||||||
- 2.4.180
|
- 2.4.180
|
||||||
- 2.4.190
|
- 2.4.190
|
||||||
|
- 2.4.200
|
||||||
- Other (please provide detail below)
|
- Other (please provide detail below)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
2
.github/workflows/pythontest.yml
vendored
2
.github/workflows/pythontest.yml
vendored
@@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- "salt/sensoroni/files/analyzers/**"
|
- "salt/sensoroni/files/analyzers/**"
|
||||||
- "salt/manager/tools/sbin"
|
- "salt/manager/tools/sbin/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ base:
|
|||||||
- secrets
|
- secrets
|
||||||
- manager.soc_manager
|
- manager.soc_manager
|
||||||
- manager.adv_manager
|
- manager.adv_manager
|
||||||
- idstools.soc_idstools
|
|
||||||
- idstools.adv_idstools
|
|
||||||
- logstash.nodes
|
- logstash.nodes
|
||||||
- logstash.soc_logstash
|
- logstash.soc_logstash
|
||||||
- logstash.adv_logstash
|
- logstash.adv_logstash
|
||||||
@@ -117,8 +115,6 @@ base:
|
|||||||
- elastalert.adv_elastalert
|
- elastalert.adv_elastalert
|
||||||
- manager.soc_manager
|
- manager.soc_manager
|
||||||
- manager.adv_manager
|
- manager.adv_manager
|
||||||
- idstools.soc_idstools
|
|
||||||
- idstools.adv_idstools
|
|
||||||
- soc.soc_soc
|
- soc.soc_soc
|
||||||
- soc.adv_soc
|
- soc.adv_soc
|
||||||
- kibana.soc_kibana
|
- kibana.soc_kibana
|
||||||
@@ -158,8 +154,6 @@ base:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
- secrets
|
- secrets
|
||||||
- healthcheck.standalone
|
- healthcheck.standalone
|
||||||
- idstools.soc_idstools
|
|
||||||
- idstools.adv_idstools
|
|
||||||
- kratos.soc_kratos
|
- kratos.soc_kratos
|
||||||
- kratos.adv_kratos
|
- kratos.adv_kratos
|
||||||
- hydra.soc_hydra
|
- hydra.soc_hydra
|
||||||
|
|||||||
@@ -172,7 +172,15 @@ MANAGER_HOSTNAME = socket.gethostname()
|
|||||||
|
|
||||||
def _download_image():
|
def _download_image():
|
||||||
"""
|
"""
|
||||||
Download and validate the Oracle Linux KVM image.
|
Download and validate the Oracle Linux KVM image with retry logic and progress monitoring.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Detects stalled downloads (no progress for 30 seconds)
|
||||||
|
- Retries up to 3 times on failure
|
||||||
|
- Connection timeout of 30 seconds
|
||||||
|
- Read timeout of 60 seconds
|
||||||
|
- Cleans up partial downloads on failure
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if successful or file exists with valid checksum, False on error
|
bool: True if successful or file exists with valid checksum, False on error
|
||||||
"""
|
"""
|
||||||
@@ -185,45 +193,107 @@ def _download_image():
|
|||||||
os.unlink(IMAGE_PATH)
|
os.unlink(IMAGE_PATH)
|
||||||
|
|
||||||
log.info("Starting image download process")
|
log.info("Starting image download process")
|
||||||
|
|
||||||
|
# Retry configuration
|
||||||
|
max_attempts = 3
|
||||||
|
retry_delay = 5 # seconds to wait between retry attempts
|
||||||
|
stall_timeout = 30 # seconds without progress before considering download stalled
|
||||||
|
connection_timeout = 30 # seconds to establish connection
|
||||||
|
read_timeout = 60 # seconds to wait for data chunks
|
||||||
|
|
||||||
|
for attempt in range(1, max_attempts + 1):
|
||||||
|
log.info("Download attempt %d of %d", attempt, max_attempts)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Download file with timeouts
|
||||||
|
log.info("Downloading Oracle Linux KVM image from %s to %s", IMAGE_URL, IMAGE_PATH)
|
||||||
|
response = requests.get(
|
||||||
|
IMAGE_URL,
|
||||||
|
stream=True,
|
||||||
|
timeout=(connection_timeout, read_timeout)
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
try:
|
# Get total file size for progress tracking
|
||||||
# Download file
|
total_size = int(response.headers.get('content-length', 0))
|
||||||
log.info("Downloading Oracle Linux KVM image from %s to %s", IMAGE_URL, IMAGE_PATH)
|
downloaded_size = 0
|
||||||
response = requests.get(IMAGE_URL, stream=True)
|
last_log_time = 0
|
||||||
response.raise_for_status()
|
last_progress_time = time.time()
|
||||||
|
last_downloaded_size = 0
|
||||||
|
|
||||||
# Get total file size for progress tracking
|
# Save file with progress logging and stall detection
|
||||||
total_size = int(response.headers.get('content-length', 0))
|
with salt.utils.files.fopen(IMAGE_PATH, 'wb') as f:
|
||||||
downloaded_size = 0
|
for chunk in response.iter_content(chunk_size=8192):
|
||||||
last_log_time = 0
|
if chunk: # filter out keep-alive new chunks
|
||||||
|
f.write(chunk)
|
||||||
|
downloaded_size += len(chunk)
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# Check for stalled download
|
||||||
|
if downloaded_size > last_downloaded_size:
|
||||||
|
# Progress made, reset stall timer
|
||||||
|
last_progress_time = current_time
|
||||||
|
last_downloaded_size = downloaded_size
|
||||||
|
elif current_time - last_progress_time > stall_timeout:
|
||||||
|
# No progress for stall_timeout seconds
|
||||||
|
raise Exception(
|
||||||
|
f"Download stalled: no progress for {stall_timeout} seconds "
|
||||||
|
f"at {downloaded_size}/{total_size} bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Log progress every second
|
||||||
|
if current_time - last_log_time >= 1:
|
||||||
|
progress = (downloaded_size / total_size) * 100 if total_size > 0 else 0
|
||||||
|
log.info("Progress - %.1f%% (%d/%d bytes)",
|
||||||
|
progress, downloaded_size, total_size)
|
||||||
|
last_log_time = current_time
|
||||||
|
|
||||||
# Save file with progress logging
|
# Validate downloaded file
|
||||||
with salt.utils.files.fopen(IMAGE_PATH, 'wb') as f:
|
log.info("Download complete, validating checksum...")
|
||||||
for chunk in response.iter_content(chunk_size=8192):
|
if not _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256):
|
||||||
f.write(chunk)
|
log.error("Checksum validation failed on attempt %d", attempt)
|
||||||
downloaded_size += len(chunk)
|
os.unlink(IMAGE_PATH)
|
||||||
|
if attempt < max_attempts:
|
||||||
|
log.info("Will retry download...")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
log.error("All download attempts failed due to checksum mismatch")
|
||||||
|
return False
|
||||||
|
|
||||||
|
log.info("Successfully downloaded and validated Oracle Linux KVM image")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except requests.exceptions.Timeout as e:
|
||||||
|
log.error("Download attempt %d failed: Timeout - %s", attempt, str(e))
|
||||||
|
if os.path.exists(IMAGE_PATH):
|
||||||
|
os.unlink(IMAGE_PATH)
|
||||||
|
if attempt < max_attempts:
|
||||||
|
log.info("Will retry download in %d seconds...", retry_delay)
|
||||||
|
time.sleep(retry_delay)
|
||||||
|
else:
|
||||||
|
log.error("All download attempts failed due to timeout")
|
||||||
|
|
||||||
# Log progress every second
|
except requests.exceptions.RequestException as e:
|
||||||
current_time = time.time()
|
log.error("Download attempt %d failed: Network error - %s", attempt, str(e))
|
||||||
if current_time - last_log_time >= 1:
|
if os.path.exists(IMAGE_PATH):
|
||||||
progress = (downloaded_size / total_size) * 100 if total_size > 0 else 0
|
os.unlink(IMAGE_PATH)
|
||||||
log.info("Progress - %.1f%% (%d/%d bytes)",
|
if attempt < max_attempts:
|
||||||
progress, downloaded_size, total_size)
|
log.info("Will retry download in %d seconds...", retry_delay)
|
||||||
last_log_time = current_time
|
time.sleep(retry_delay)
|
||||||
|
else:
|
||||||
# Validate downloaded file
|
log.error("All download attempts failed due to network errors")
|
||||||
if not _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256):
|
|
||||||
os.unlink(IMAGE_PATH)
|
except Exception as e:
|
||||||
return False
|
log.error("Download attempt %d failed: %s", attempt, str(e))
|
||||||
|
if os.path.exists(IMAGE_PATH):
|
||||||
log.info("Successfully downloaded and validated Oracle Linux KVM image")
|
os.unlink(IMAGE_PATH)
|
||||||
return True
|
if attempt < max_attempts:
|
||||||
|
log.info("Will retry download in %d seconds...", retry_delay)
|
||||||
except Exception as e:
|
time.sleep(retry_delay)
|
||||||
log.error("Error downloading hypervisor image: %s", str(e))
|
else:
|
||||||
if os.path.exists(IMAGE_PATH):
|
log.error("All download attempts failed")
|
||||||
os.unlink(IMAGE_PATH)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _check_ssh_keys_exist():
|
def _check_ssh_keys_exist():
|
||||||
"""
|
"""
|
||||||
@@ -419,25 +489,28 @@ def _ensure_hypervisor_host_dir(minion_id: str = None):
|
|||||||
log.error(f"Error creating hypervisor host directory: {str(e)}")
|
log.error(f"Error creating hypervisor host directory: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _apply_dyanno_hypervisor_state():
|
def _apply_dyanno_hypervisor_state(status):
|
||||||
"""
|
"""
|
||||||
Apply the soc.dyanno.hypervisor state on the salt master.
|
Apply the soc.dyanno.hypervisor state on the salt master.
|
||||||
|
|
||||||
This function applies the soc.dyanno.hypervisor state on the salt master
|
This function applies the soc.dyanno.hypervisor state on the salt master
|
||||||
to update the hypervisor annotation and ensure all hypervisor host directories exist.
|
to update the hypervisor annotation and ensure all hypervisor host directories exist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
status: Status passed to the hypervisor annotation state
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if state was applied successfully, False otherwise
|
bool: True if state was applied successfully, False otherwise
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
log.info("Applying soc.dyanno.hypervisor state on salt master")
|
log.info(f"Applying soc.dyanno.hypervisor state on salt master with status: {status}")
|
||||||
|
|
||||||
# Initialize the LocalClient
|
# Initialize the LocalClient
|
||||||
local = salt.client.LocalClient()
|
local = salt.client.LocalClient()
|
||||||
|
|
||||||
# Target the salt master to apply the soc.dyanno.hypervisor state
|
# Target the salt master to apply the soc.dyanno.hypervisor state
|
||||||
target = MANAGER_HOSTNAME + '_*'
|
target = MANAGER_HOSTNAME + '_*'
|
||||||
state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor', "pillar={'baseDomain': {'status': 'PreInit'}}", 'concurrent=True'], tgt_type='glob')
|
state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor', f"pillar={{'baseDomain': {{'status': '{status}'}}}}", 'concurrent=True'], tgt_type='glob')
|
||||||
log.debug(f"state_result: {state_result}")
|
log.debug(f"state_result: {state_result}")
|
||||||
# Check if state was applied successfully
|
# Check if state was applied successfully
|
||||||
if state_result:
|
if state_result:
|
||||||
@@ -454,17 +527,17 @@ def _apply_dyanno_hypervisor_state():
|
|||||||
success = False
|
success = False
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
log.info("Successfully applied soc.dyanno.hypervisor state")
|
log.info(f"Successfully applied soc.dyanno.hypervisor state with status: {status}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
log.error("Failed to apply soc.dyanno.hypervisor state")
|
log.error(f"Failed to apply soc.dyanno.hypervisor state with status: {status}")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
log.error("No response from salt master when applying soc.dyanno.hypervisor state")
|
log.error(f"No response from salt master when applying soc.dyanno.hypervisor state with status: {status}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error applying soc.dyanno.hypervisor state: {str(e)}")
|
log.error(f"Error applying soc.dyanno.hypervisor state with status: {status}: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _apply_cloud_config_state():
|
def _apply_cloud_config_state():
|
||||||
@@ -598,11 +671,6 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id
|
|||||||
log.warning("Failed to apply salt.cloud.config state, continuing with setup")
|
log.warning("Failed to apply salt.cloud.config state, continuing with setup")
|
||||||
# We don't return an error here as we want to continue with the setup process
|
# We don't return an error here as we want to continue with the setup process
|
||||||
|
|
||||||
# Apply the soc.dyanno.hypervisor state on the salt master
|
|
||||||
if not _apply_dyanno_hypervisor_state():
|
|
||||||
log.warning("Failed to apply soc.dyanno.hypervisor state, continuing with setup")
|
|
||||||
# We don't return an error here as we want to continue with the setup process
|
|
||||||
|
|
||||||
log.info("Starting setup_environment in setup_hypervisor runner")
|
log.info("Starting setup_environment in setup_hypervisor runner")
|
||||||
|
|
||||||
# Check if environment is already set up
|
# Check if environment is already set up
|
||||||
@@ -616,9 +684,12 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id
|
|||||||
|
|
||||||
# Handle image setup if needed
|
# Handle image setup if needed
|
||||||
if not image_valid:
|
if not image_valid:
|
||||||
|
_apply_dyanno_hypervisor_state('ImageDownloadStart')
|
||||||
log.info("Starting image download/validation process")
|
log.info("Starting image download/validation process")
|
||||||
if not _download_image():
|
if not _download_image():
|
||||||
log.error("Image download failed")
|
log.error("Image download failed")
|
||||||
|
# Update hypervisor annotation with failure status
|
||||||
|
_apply_dyanno_hypervisor_state('ImageDownloadFailed')
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'error': 'Image download failed',
|
'error': 'Image download failed',
|
||||||
@@ -631,6 +702,8 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id
|
|||||||
log.info("Setting up SSH keys")
|
log.info("Setting up SSH keys")
|
||||||
if not _setup_ssh_keys():
|
if not _setup_ssh_keys():
|
||||||
log.error("SSH key setup failed")
|
log.error("SSH key setup failed")
|
||||||
|
# Update hypervisor annotation with failure status
|
||||||
|
_apply_dyanno_hypervisor_state('SSHKeySetupFailed')
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'error': 'SSH key setup failed',
|
'error': 'SSH key setup failed',
|
||||||
@@ -655,6 +728,12 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id
|
|||||||
success = vm_result.get('success', False)
|
success = vm_result.get('success', False)
|
||||||
log.info("Setup environment completed with status: %s", "SUCCESS" if success else "FAILED")
|
log.info("Setup environment completed with status: %s", "SUCCESS" if success else "FAILED")
|
||||||
|
|
||||||
|
# Update hypervisor annotation with success status
|
||||||
|
if success:
|
||||||
|
_apply_dyanno_hypervisor_state('PreInit')
|
||||||
|
else:
|
||||||
|
_apply_dyanno_hypervisor_state('SetupFailed')
|
||||||
|
|
||||||
# If setup was successful and we have a minion_id, run highstate
|
# If setup was successful and we have a minion_id, run highstate
|
||||||
if success and minion_id:
|
if success and minion_id:
|
||||||
log.info("Running highstate on hypervisor %s", minion_id)
|
log.info("Running highstate on hypervisor %s", minion_id)
|
||||||
|
|||||||
@@ -38,8 +38,6 @@
|
|||||||
'hydra',
|
'hydra',
|
||||||
'elasticfleet',
|
'elasticfleet',
|
||||||
'elastic-fleet-package-registry',
|
'elastic-fleet-package-registry',
|
||||||
'idstools',
|
|
||||||
'suricata.manager',
|
|
||||||
'utility'
|
'utility'
|
||||||
] %}
|
] %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
|
{% set PCAP_BPF_STATUS = 0 %}
|
||||||
|
{% set STENO_BPF_COMPILED = "" %}
|
||||||
|
|
||||||
{% if GLOBALS.pcap_engine == "TRANSITION" %}
|
{% if GLOBALS.pcap_engine == "TRANSITION" %}
|
||||||
{% set PCAPBPF = ["ip and host 255.255.255.1 and port 1"] %}
|
{% set PCAPBPF = ["ip and host 255.255.255.1 and port 1"] %}
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -8,3 +11,11 @@
|
|||||||
{{ MACROS.remove_comments(BPFMERGED, 'pcap') }}
|
{{ MACROS.remove_comments(BPFMERGED, 'pcap') }}
|
||||||
{% set PCAPBPF = BPFMERGED.pcap %}
|
{% set PCAPBPF = BPFMERGED.pcap %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if PCAPBPF %}
|
||||||
|
{% set PCAP_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ PCAPBPF|join(" "), cwd='/root') %}
|
||||||
|
{% if PCAP_BPF_CALC['retcode'] == 0 %}
|
||||||
|
{% set PCAP_BPF_STATUS = 1 %}
|
||||||
|
{% set STENO_BPF_COMPILED = ",\\\"--filter=" + PCAP_BPF_CALC['stdout'] + "\\\"" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
bpf:
|
bpf:
|
||||||
pcap:
|
pcap:
|
||||||
description: List of BPF filters to apply to Stenographer.
|
description: List of BPF filters to apply to the PCAP engine.
|
||||||
multiline: True
|
multiline: True
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
helpLink: bpf.html
|
helpLink: bpf.html
|
||||||
suricata:
|
suricata:
|
||||||
description: List of BPF filters to apply to Suricata.
|
description: List of BPF filters to apply to Suricata. This will apply to alerts and, if enabled, to metadata and PCAP logs generated by Suricata.
|
||||||
multiline: True
|
multiline: True
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
helpLink: bpf.html
|
helpLink: bpf.html
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
|
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
|
||||||
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
|
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
|
||||||
|
{% set SURICATA_BPF_STATUS = 0 %}
|
||||||
{% import 'bpf/macros.jinja' as MACROS %}
|
{% import 'bpf/macros.jinja' as MACROS %}
|
||||||
|
|
||||||
{{ MACROS.remove_comments(BPFMERGED, 'suricata') }}
|
{{ MACROS.remove_comments(BPFMERGED, 'suricata') }}
|
||||||
|
|
||||||
{% set SURICATABPF = BPFMERGED.suricata %}
|
{% set SURICATABPF = BPFMERGED.suricata %}
|
||||||
|
|
||||||
|
{% if SURICATABPF %}
|
||||||
|
{% set SURICATA_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ SURICATABPF|join(" "), cwd='/root') %}
|
||||||
|
{% if SURICATA_BPF_CALC['retcode'] == 0 %}
|
||||||
|
{% set SURICATA_BPF_STATUS = 1 %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
|
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
|
||||||
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
|
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
|
||||||
|
{% set ZEEK_BPF_STATUS = 0 %}
|
||||||
{% import 'bpf/macros.jinja' as MACROS %}
|
{% import 'bpf/macros.jinja' as MACROS %}
|
||||||
|
|
||||||
{{ MACROS.remove_comments(BPFMERGED, 'zeek') }}
|
{{ MACROS.remove_comments(BPFMERGED, 'zeek') }}
|
||||||
|
|
||||||
{% set ZEEKBPF = BPFMERGED.zeek %}
|
{% set ZEEKBPF = BPFMERGED.zeek %}
|
||||||
|
|
||||||
|
{% if ZEEKBPF %}
|
||||||
|
{% set ZEEK_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ ZEEKBPF|join(" "), cwd='/root') %}
|
||||||
|
{% if ZEEK_BPF_CALC['retcode'] == 0 %}
|
||||||
|
{% set ZEEK_BPF_STATUS = 1 %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -29,9 +29,26 @@ fi
|
|||||||
|
|
||||||
interface="$1"
|
interface="$1"
|
||||||
shift
|
shift
|
||||||
tcpdump -i $interface -ddd $@ | tail -n+2 |
|
|
||||||
while read line; do
|
# Capture tcpdump output and exit code
|
||||||
|
tcpdump_output=$(tcpdump -i "$interface" -ddd "$@" 2>&1)
|
||||||
|
tcpdump_exit=$?
|
||||||
|
|
||||||
|
if [ $tcpdump_exit -ne 0 ]; then
|
||||||
|
echo "$tcpdump_output" >&2
|
||||||
|
exit $tcpdump_exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process the output, skipping the first line
|
||||||
|
echo "$tcpdump_output" | tail -n+2 | while read -r line; do
|
||||||
cols=( $line )
|
cols=( $line )
|
||||||
printf "%04x%02x%02x%08x" ${cols[0]} ${cols[1]} ${cols[2]} ${cols[3]}
|
printf "%04x%02x%02x%08x" "${cols[0]}" "${cols[1]}" "${cols[2]}" "${cols[3]}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Check if the pipeline succeeded
|
||||||
|
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
exit 0
|
||||||
|
|||||||
@@ -220,12 +220,22 @@ compare_es_versions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
copy_new_files() {
|
copy_new_files() {
|
||||||
|
# Define files to exclude from deletion (relative to their respective base directories)
|
||||||
|
local EXCLUDE_FILES=(
|
||||||
|
"salt/hypervisor/soc_hypervisor.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build rsync exclude arguments
|
||||||
|
local EXCLUDE_ARGS=()
|
||||||
|
for file in "${EXCLUDE_FILES[@]}"; do
|
||||||
|
EXCLUDE_ARGS+=(--exclude="$file")
|
||||||
|
done
|
||||||
|
|
||||||
# Copy new files over to the salt dir
|
# Copy new files over to the salt dir
|
||||||
cd $UPDATE_DIR
|
cd $UPDATE_DIR
|
||||||
rsync -a salt $DEFAULT_SALT_DIR/ --delete
|
rsync -a salt $DEFAULT_SALT_DIR/ --delete "${EXCLUDE_ARGS[@]}"
|
||||||
rsync -a pillar $DEFAULT_SALT_DIR/ --delete
|
rsync -a pillar $DEFAULT_SALT_DIR/ --delete "${EXCLUDE_ARGS[@]}"
|
||||||
chown -R socore:socore $DEFAULT_SALT_DIR/
|
chown -R socore:socore $DEFAULT_SALT_DIR/
|
||||||
chmod 755 $DEFAULT_SALT_DIR/pillar/firewall/addfirewall.sh
|
|
||||||
cd /tmp
|
cd /tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +395,7 @@ is_manager_node() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_sensor_node() {
|
is_sensor_node() {
|
||||||
# Check to see if this is a sensor (forward) node
|
# Check to see if this is a sensor node
|
||||||
is_single_node_grid && return 0
|
is_single_node_grid && return 0
|
||||||
grep "role: so-" /etc/salt/grains | grep -E "sensor|heavynode" &> /dev/null
|
grep "role: so-" /etc/salt/grains | grep -E "sensor|heavynode" &> /dev/null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ container_list() {
|
|||||||
if [ $MANAGERCHECK == 'so-import' ]; then
|
if [ $MANAGERCHECK == 'so-import' ]; then
|
||||||
TRUSTED_CONTAINERS=(
|
TRUSTED_CONTAINERS=(
|
||||||
"so-elasticsearch"
|
"so-elasticsearch"
|
||||||
"so-idstools"
|
|
||||||
"so-influxdb"
|
"so-influxdb"
|
||||||
"so-kibana"
|
"so-kibana"
|
||||||
"so-kratos"
|
"so-kratos"
|
||||||
@@ -49,7 +48,6 @@ container_list() {
|
|||||||
"so-elastic-fleet-package-registry"
|
"so-elastic-fleet-package-registry"
|
||||||
"so-elasticsearch"
|
"so-elasticsearch"
|
||||||
"so-idh"
|
"so-idh"
|
||||||
"so-idstools"
|
|
||||||
"so-influxdb"
|
"so-influxdb"
|
||||||
"so-kafka"
|
"so-kafka"
|
||||||
"so-kibana"
|
"so-kibana"
|
||||||
@@ -62,8 +60,6 @@ container_list() {
|
|||||||
"so-soc"
|
"so-soc"
|
||||||
"so-steno"
|
"so-steno"
|
||||||
"so-strelka-backend"
|
"so-strelka-backend"
|
||||||
"so-strelka-filestream"
|
|
||||||
"so-strelka-frontend"
|
|
||||||
"so-strelka-manager"
|
"so-strelka-manager"
|
||||||
"so-suricata"
|
"so-suricata"
|
||||||
"so-telegraf"
|
"so-telegraf"
|
||||||
@@ -71,7 +67,6 @@ container_list() {
|
|||||||
)
|
)
|
||||||
else
|
else
|
||||||
TRUSTED_CONTAINERS=(
|
TRUSTED_CONTAINERS=(
|
||||||
"so-idstools"
|
|
||||||
"so-elasticsearch"
|
"so-elasticsearch"
|
||||||
"so-logstash"
|
"so-logstash"
|
||||||
"so-nginx"
|
"so-nginx"
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ function suricata() {
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \
|
-v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \
|
||||||
-v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \
|
-v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \
|
||||||
-v /opt/so/conf/suricata/rules:/etc/suricata/rules:ro \
|
-v /opt/so/rules/suricata/:/etc/suricata/rules:ro \
|
||||||
-v ${LOG_PATH}:/var/log/suricata/:rw \
|
-v ${LOG_PATH}:/var/log/suricata/:rw \
|
||||||
-v ${NSM_PATH}/:/nsm/:rw \
|
-v ${NSM_PATH}/:/nsm/:rw \
|
||||||
-v "$PCAP:/input.pcap:ro" \
|
-v "$PCAP:/input.pcap:ro" \
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ docker:
|
|||||||
custom_bind_mounts: []
|
custom_bind_mounts: []
|
||||||
extra_hosts: []
|
extra_hosts: []
|
||||||
extra_env: []
|
extra_env: []
|
||||||
'so-idstools':
|
|
||||||
final_octet: 25
|
|
||||||
custom_bind_mounts: []
|
|
||||||
extra_hosts: []
|
|
||||||
extra_env: []
|
|
||||||
'so-influxdb':
|
'so-influxdb':
|
||||||
final_octet: 26
|
final_octet: 26
|
||||||
port_bindings:
|
port_bindings:
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ docker:
|
|||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
so-elastic-fleet: *dockerOptions
|
so-elastic-fleet: *dockerOptions
|
||||||
so-elasticsearch: *dockerOptions
|
so-elasticsearch: *dockerOptions
|
||||||
so-idstools: *dockerOptions
|
|
||||||
so-influxdb: *dockerOptions
|
so-influxdb: *dockerOptions
|
||||||
so-kibana: *dockerOptions
|
so-kibana: *dockerOptions
|
||||||
so-kratos: *dockerOptions
|
so-kratos: *dockerOptions
|
||||||
@@ -102,4 +101,4 @@ docker:
|
|||||||
multiline: True
|
multiline: True
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
so-zeek: *dockerOptions
|
so-zeek: *dockerOptions
|
||||||
so-kafka: *dockerOptions
|
so-kafka: *dockerOptions
|
||||||
|
|||||||
34
salt/elasticfleet/config.map.jinja
Normal file
34
salt/elasticfleet/config.map.jinja
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
Elastic License 2.0. #}
|
||||||
|
|
||||||
|
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||||
|
|
||||||
|
{# advanced config_yaml options for elasticfleet logstash output #}
|
||||||
|
{% set ADV_OUTPUT_LOGSTASH_RAW = ELASTICFLEETMERGED.config.outputs.logstash %}
|
||||||
|
{% set ADV_OUTPUT_LOGSTASH = {} %}
|
||||||
|
{% for k, v in ADV_OUTPUT_LOGSTASH_RAW.items() %}
|
||||||
|
{% if v != "" and v is not none %}
|
||||||
|
{% if k == 'queue_mem_events' %}
|
||||||
|
{# rename queue_mem_events queue.mem.events #}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({'queue.mem.events':v}) %}
|
||||||
|
{% elif k == 'loadbalance' %}
|
||||||
|
{% if v %}
|
||||||
|
{# only include loadbalance config when its True #}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% set LOGSTASH_CONFIG_YAML_RAW = [] %}
|
||||||
|
{% if ADV_OUTPUT_LOGSTASH %}
|
||||||
|
{% for k, v in ADV_OUTPUT_LOGSTASH.items() %}
|
||||||
|
{% do LOGSTASH_CONFIG_YAML_RAW.append(k ~ ': ' ~ v) %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set LOGSTASH_CONFIG_YAML = LOGSTASH_CONFIG_YAML_RAW | join('\\n') if LOGSTASH_CONFIG_YAML_RAW else '' %}
|
||||||
@@ -10,12 +10,19 @@ elasticfleet:
|
|||||||
grid_enrollment: ''
|
grid_enrollment: ''
|
||||||
defend_filters:
|
defend_filters:
|
||||||
enable_auto_configuration: False
|
enable_auto_configuration: False
|
||||||
|
outputs:
|
||||||
|
logstash:
|
||||||
|
bulk_max_size: ''
|
||||||
|
worker: ''
|
||||||
|
queue_mem_events: ''
|
||||||
|
timeout: ''
|
||||||
|
loadbalance: False
|
||||||
|
compression_level: ''
|
||||||
subscription_integrations: False
|
subscription_integrations: False
|
||||||
auto_upgrade_integrations: False
|
auto_upgrade_integrations: False
|
||||||
logging:
|
logging:
|
||||||
zeek:
|
zeek:
|
||||||
excluded:
|
excluded:
|
||||||
- analyzer
|
|
||||||
- broker
|
- broker
|
||||||
- capture_loss
|
- capture_loss
|
||||||
- cluster
|
- cluster
|
||||||
|
|||||||
@@ -32,6 +32,17 @@ so-elastic-fleet-auto-configure-logstash-outputs:
|
|||||||
- retry:
|
- retry:
|
||||||
attempts: 4
|
attempts: 4
|
||||||
interval: 30
|
interval: 30
|
||||||
|
|
||||||
|
{# Separate from above in order to catch elasticfleet-logstash.crt changes and force update to fleet output policy #}
|
||||||
|
so-elastic-fleet-auto-configure-logstash-outputs-force:
|
||||||
|
cmd.run:
|
||||||
|
- name: /usr/sbin/so-elastic-fleet-outputs-update --certs
|
||||||
|
- retry:
|
||||||
|
attempts: 4
|
||||||
|
interval: 30
|
||||||
|
- onchanges:
|
||||||
|
- x509: etc_elasticfleet_logstash_crt
|
||||||
|
- x509: elasticfleet_kafka_crt
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# If enabled, automatically update Fleet Server URLs & ES Connection
|
# If enabled, automatically update Fleet Server URLs & ES Connection
|
||||||
|
|||||||
@@ -2,26 +2,30 @@
|
|||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use
|
# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use
|
||||||
# this file except in compliance with the Elastic License 2.0.
|
# this file except in compliance with the Elastic License 2.0.
|
||||||
|
|
||||||
{%- set GRIDNODETOKENGENERAL = salt['pillar.get']('global:fleet_grid_enrollment_token_general') -%}
|
{% set GRIDNODETOKEN = salt['pillar.get']('global:fleet_grid_enrollment_token_general') -%}
|
||||||
{%- set GRIDNODETOKENHEAVY = salt['pillar.get']('global:fleet_grid_enrollment_token_heavy') -%}
|
{% if grains.role == 'so-heavynode' %}
|
||||||
|
{% set GRIDNODETOKEN = salt['pillar.get']('global:fleet_grid_enrollment_token_heavy') -%}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% set AGENT_STATUS = salt['service.available']('elastic-agent') %}
|
{% set AGENT_STATUS = salt['service.available']('elastic-agent') %}
|
||||||
{% if not AGENT_STATUS %}
|
{% if not AGENT_STATUS %}
|
||||||
|
|
||||||
{% if grains.role not in ['so-heavynode'] %}
|
pull_agent_installer:
|
||||||
run_installer:
|
file.managed:
|
||||||
cmd.script:
|
- name: /opt/so/so-elastic-agent_linux_amd64
|
||||||
- name: salt://elasticfleet/files/so_agent-installers/so-elastic-agent_linux_amd64
|
- source: salt://elasticfleet/files/so_agent-installers/so-elastic-agent_linux_amd64
|
||||||
- cwd: /opt/so
|
- mode: 755
|
||||||
- args: -token={{ GRIDNODETOKENGENERAL }}
|
- makedirs: True
|
||||||
- retry: True
|
|
||||||
{% else %}
|
|
||||||
run_installer:
|
|
||||||
cmd.script:
|
|
||||||
- name: salt://elasticfleet/files/so_agent-installers/so-elastic-agent_linux_amd64
|
|
||||||
- cwd: /opt/so
|
|
||||||
- args: -token={{ GRIDNODETOKENHEAVY }}
|
|
||||||
- retry: True
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
run_installer:
|
||||||
|
cmd.run:
|
||||||
|
- name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }}
|
||||||
|
- cwd: /opt/so
|
||||||
|
- retry:
|
||||||
|
attempts: 3
|
||||||
|
interval: 20
|
||||||
|
|
||||||
|
cleanup_agent_installer:
|
||||||
|
file.absent:
|
||||||
|
- name: /opt/so/so-elastic-agent_linux_amd64
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -121,6 +121,9 @@
|
|||||||
"phases": {
|
"phases": {
|
||||||
"cold": {
|
"cold": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"allocate":{
|
||||||
|
"number_of_replicas": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 0}
|
"set_priority": {"priority": 0}
|
||||||
},
|
},
|
||||||
"min_age": "60d"
|
"min_age": "60d"
|
||||||
@@ -137,12 +140,31 @@
|
|||||||
"max_age": "30d",
|
"max_age": "30d",
|
||||||
"max_primary_shard_size": "50gb"
|
"max_primary_shard_size": "50gb"
|
||||||
},
|
},
|
||||||
|
"forcemerge":{
|
||||||
|
"max_num_segments": ""
|
||||||
|
},
|
||||||
|
"shrink":{
|
||||||
|
"max_primary_shard_size": "",
|
||||||
|
"method": "COUNT",
|
||||||
|
"number_of_shards": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 100}
|
"set_priority": {"priority": 100}
|
||||||
},
|
},
|
||||||
"min_age": "0ms"
|
"min_age": "0ms"
|
||||||
},
|
},
|
||||||
"warm": {
|
"warm": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"allocate": {
|
||||||
|
"number_of_replicas": ""
|
||||||
|
},
|
||||||
|
"forcemerge": {
|
||||||
|
"max_num_segments": ""
|
||||||
|
},
|
||||||
|
"shrink":{
|
||||||
|
"max_primary_shard_size": "",
|
||||||
|
"method": "COUNT",
|
||||||
|
"number_of_shards": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 50}
|
"set_priority": {"priority": 50}
|
||||||
},
|
},
|
||||||
"min_age": "30d"
|
"min_age": "30d"
|
||||||
|
|||||||
@@ -50,6 +50,46 @@ elasticfleet:
|
|||||||
global: True
|
global: True
|
||||||
forcedType: bool
|
forcedType: bool
|
||||||
helpLink: elastic-fleet.html
|
helpLink: elastic-fleet.html
|
||||||
|
outputs:
|
||||||
|
logstash:
|
||||||
|
bulk_max_size:
|
||||||
|
description: The maximum number of events to bulk in a single Logstash request.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
worker:
|
||||||
|
description: The number of workers per configured host publishing events.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: true
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
queue_mem_events:
|
||||||
|
title: queued events
|
||||||
|
description: The number of events the queue can store. This value should be evenly divisible by the smaller of 'bulk_max_size' to avoid sending partial batches to the output.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
timeout:
|
||||||
|
description: The number of seconds to wait for responses from the Logstash server before timing out. Eg 30s
|
||||||
|
regex: ^[0-9]+s$
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
loadbalance:
|
||||||
|
description: If true and multiple Logstash hosts are configured, the output plugin load balances published events onto all Logstash hosts. If false, the output plugin sends all events to one host (determined at random) and switches to another host if the selected one becomes unresponsive.
|
||||||
|
forcedType: bool
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
compression_level:
|
||||||
|
description: The gzip compression level. The compression level must be in the range of 1 (best speed) to 9 (best compression).
|
||||||
|
regex: ^[1-9]$
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
server:
|
server:
|
||||||
custom_fqdn:
|
custom_fqdn:
|
||||||
description: Custom FQDN for Agents to connect to. One per line.
|
description: Custom FQDN for Agents to connect to. One per line.
|
||||||
|
|||||||
@@ -3,11 +3,36 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use
|
# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use
|
||||||
# this file except in compliance with the Elastic License 2.0.
|
# this file except in compliance with the Elastic License 2.0.
|
||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{%- from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
{%- from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||||
|
{%- from 'elasticfleet/config.map.jinja' import LOGSTASH_CONFIG_YAML %}
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
FORCE_UPDATE=false
|
||||||
|
UPDATE_CERTS=false
|
||||||
|
LOGSTASH_PILLAR_CONFIG_YAML="{{ LOGSTASH_CONFIG_YAML }}"
|
||||||
|
LOGSTASH_PILLAR_STATE_FILE="/opt/so/state/esfleet_logstash_config_pillar"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-f|--force)
|
||||||
|
FORCE_UPDATE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-c| --certs)
|
||||||
|
UPDATE_CERTS=true
|
||||||
|
FORCE_UPDATE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
echo "Usage: $0 [-f|--force] [-c|--certs]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# Only run on Managers
|
# Only run on Managers
|
||||||
if ! is_manager_node; then
|
if ! is_manager_node; then
|
||||||
printf "Not a Manager Node... Exiting"
|
printf "Not a Manager Node... Exiting"
|
||||||
@@ -17,17 +42,49 @@ fi
|
|||||||
function update_logstash_outputs() {
|
function update_logstash_outputs() {
|
||||||
if logstash_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_logstash" --retry 3 --retry-delay 10 --fail 2>/dev/null); then
|
if logstash_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_logstash" --retry 3 --retry-delay 10 --fail 2>/dev/null); then
|
||||||
SSL_CONFIG=$(echo "$logstash_policy" | jq -r '.item.ssl')
|
SSL_CONFIG=$(echo "$logstash_policy" | jq -r '.item.ssl')
|
||||||
|
LOGSTASHKEY=$(openssl rsa -in /etc/pki/elasticfleet-logstash.key)
|
||||||
|
LOGSTASHCRT=$(openssl x509 -in /etc/pki/elasticfleet-logstash.crt)
|
||||||
|
LOGSTASHCA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
||||||
|
# Revert escaped \\n to \n for jq
|
||||||
|
LOGSTASH_PILLAR_CONFIG_YAML=$(printf '%b' "$LOGSTASH_PILLAR_CONFIG_YAML")
|
||||||
|
|
||||||
if SECRETS=$(echo "$logstash_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
if SECRETS=$(echo "$logstash_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
||||||
JSON_STRING=$(jq -n \
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
# Reuse existing secret
|
||||||
--argjson SECRETS "$SECRETS" \
|
JSON_STRING=$(jq -n \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
|
--argjson SECRETS "$SECRETS" \
|
||||||
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
||||||
|
else
|
||||||
|
# Update certs, creating new secret
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
|
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
||||||
|
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
||||||
|
--arg LOGSTASHCA "$LOGSTASHCA" \
|
||||||
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": {"certificate": $LOGSTASHCRT,"certificate_authorities":[ $LOGSTASHCA ]},"secrets": {"ssl":{"key": $LOGSTASHKEY }}}')
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
JSON_STRING=$(jq -n \
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
# Reuse existing ssl config
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
JSON_STRING=$(jq -n \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": $SSL_CONFIG}')
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": $SSL_CONFIG}')
|
||||||
|
else
|
||||||
|
# Update ssl config
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
|
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
||||||
|
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
||||||
|
--arg LOGSTASHCA "$LOGSTASHCA" \
|
||||||
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": {"certificate": $LOGSTASHCRT,"key": $LOGSTASHKEY,"certificate_authorities":[ $LOGSTASHCA ]}}')
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -38,19 +95,42 @@ function update_kafka_outputs() {
|
|||||||
# Make sure SSL configuration is included in policy updates for Kafka output. SSL is configured in so-elastic-fleet-setup
|
# Make sure SSL configuration is included in policy updates for Kafka output. SSL is configured in so-elastic-fleet-setup
|
||||||
if kafka_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_kafka" --fail 2>/dev/null); then
|
if kafka_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_kafka" --fail 2>/dev/null); then
|
||||||
SSL_CONFIG=$(echo "$kafka_policy" | jq -r '.item.ssl')
|
SSL_CONFIG=$(echo "$kafka_policy" | jq -r '.item.ssl')
|
||||||
|
KAFKAKEY=$(openssl rsa -in /etc/pki/elasticfleet-kafka.key)
|
||||||
|
KAFKACRT=$(openssl x509 -in /etc/pki/elasticfleet-kafka.crt)
|
||||||
|
KAFKACA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
||||||
if SECRETS=$(echo "$kafka_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
if SECRETS=$(echo "$kafka_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
||||||
# Update policy when fleet has secrets enabled
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
JSON_STRING=$(jq -n \
|
# Update policy when fleet has secrets enabled
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
JSON_STRING=$(jq -n \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
--argjson SECRETS "$SECRETS" \
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
--argjson SECRETS "$SECRETS" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
||||||
|
else
|
||||||
|
# Update certs, creating new secret
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg KAFKAKEY "$KAFKAKEY" \
|
||||||
|
--arg KAFKACRT "$KAFKACRT" \
|
||||||
|
--arg KAFKACA "$KAFKACA" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": {"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"secrets": {"ssl":{"key": $KAFKAKEY }}}')
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# Update policy when fleet has secrets disabled or policy hasn't been force updated
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
JSON_STRING=$(jq -n \
|
# Update policy when fleet has secrets disabled or policy hasn't been force updated
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
JSON_STRING=$(jq -n \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG}')
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG}')
|
||||||
|
else
|
||||||
|
# Update ssl config
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg KAFKAKEY "$KAFKAKEY" \
|
||||||
|
--arg KAFKACRT "$KAFKACRT" \
|
||||||
|
--arg KAFKACA "$KAFKACA" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": { "certificate_authorities": [ $KAFKACA ], "certificate": $KAFKACRT, "key": $KAFKAKEY, "verification_mode": "full" }}')
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
# Update Kafka outputs
|
# Update Kafka outputs
|
||||||
curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" | jq
|
curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" | jq
|
||||||
@@ -73,7 +153,7 @@ function update_kafka_outputs() {
|
|||||||
|
|
||||||
# Get the current list of kafka outputs & hash them
|
# Get the current list of kafka outputs & hash them
|
||||||
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
||||||
CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
CURRENT_HASH=$(sha256sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
||||||
|
|
||||||
declare -a NEW_LIST=()
|
declare -a NEW_LIST=()
|
||||||
|
|
||||||
@@ -96,10 +176,19 @@ function update_kafka_outputs() {
|
|||||||
printf "Failed to query for current Logstash Outputs..."
|
printf "Failed to query for current Logstash Outputs..."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
# logstash adv config - compare pillar to last state file value
|
||||||
|
if [[ -f "$LOGSTASH_PILLAR_STATE_FILE" ]]; then
|
||||||
|
PREVIOUS_LOGSTASH_PILLAR_CONFIG_YAML=$(cat "$LOGSTASH_PILLAR_STATE_FILE")
|
||||||
|
if [[ "$LOGSTASH_PILLAR_CONFIG_YAML" != "$PREVIOUS_LOGSTASH_PILLAR_CONFIG_YAML" ]]; then
|
||||||
|
echo "Logstash pillar config has changed - forcing update"
|
||||||
|
FORCE_UPDATE=true
|
||||||
|
fi
|
||||||
|
echo "$LOGSTASH_PILLAR_CONFIG_YAML" > "$LOGSTASH_PILLAR_STATE_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# Get the current list of Logstash outputs & hash them
|
# Get the current list of Logstash outputs & hash them
|
||||||
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
||||||
CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
CURRENT_HASH=$(sha256sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
||||||
|
|
||||||
declare -a NEW_LIST=()
|
declare -a NEW_LIST=()
|
||||||
|
|
||||||
@@ -148,10 +237,10 @@ function update_kafka_outputs() {
|
|||||||
|
|
||||||
# Sort & hash the new list of Logstash Outputs
|
# Sort & hash the new list of Logstash Outputs
|
||||||
NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}")
|
NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}")
|
||||||
NEW_HASH=$(sha1sum <<< "$NEW_LIST_JSON" | awk '{print $1}')
|
NEW_HASH=$(sha256sum <<< "$NEW_LIST_JSON" | awk '{print $1}')
|
||||||
|
|
||||||
# Compare the current & new list of outputs - if different, update the Logstash outputs
|
# Compare the current & new list of outputs - if different, update the Logstash outputs
|
||||||
if [ "$NEW_HASH" = "$CURRENT_HASH" ]; then
|
if [[ "$NEW_HASH" = "$CURRENT_HASH" ]] && [[ "$FORCE_UPDATE" != "true" ]]; then
|
||||||
printf "\nHashes match - no update needed.\n"
|
printf "\nHashes match - no update needed.\n"
|
||||||
printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n"
|
printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n"
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ elasticsearch:
|
|||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 0
|
priority: 0
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 60d
|
min_age: 60d
|
||||||
delete:
|
delete:
|
||||||
actions:
|
actions:
|
||||||
@@ -84,11 +86,25 @@ elasticsearch:
|
|||||||
max_primary_shard_size: 50gb
|
max_primary_shard_size: 50gb
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 100
|
priority: 100
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 0ms
|
min_age: 0ms
|
||||||
warm:
|
warm:
|
||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
so-case:
|
so-case:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
@@ -245,7 +261,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-detection:
|
so-detection:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -584,7 +599,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-import:
|
so-import:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -932,7 +946,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-hydra:
|
so-hydra:
|
||||||
close: 30
|
close: 30
|
||||||
delete: 365
|
delete: 365
|
||||||
@@ -1043,7 +1056,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-lists:
|
so-lists:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -1127,6 +1139,8 @@ elasticsearch:
|
|||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 0
|
priority: 0
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 60d
|
min_age: 60d
|
||||||
delete:
|
delete:
|
||||||
actions:
|
actions:
|
||||||
@@ -1139,11 +1153,25 @@ elasticsearch:
|
|||||||
max_primary_shard_size: 50gb
|
max_primary_shard_size: 50gb
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 100
|
priority: 100
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 0ms
|
min_age: 0ms
|
||||||
warm:
|
warm:
|
||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
so-logs-detections_x_alerts:
|
so-logs-detections_x_alerts:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
@@ -3123,7 +3151,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-logs-system_x_application:
|
so-logs-system_x_application:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
|
|||||||
@@ -1,15 +1,79 @@
|
|||||||
{
|
{
|
||||||
"description" : "suricata.alert",
|
"description": "suricata.alert",
|
||||||
"processors" : [
|
"processors": [
|
||||||
{ "set": { "if": "ctx.event?.imported != true", "field": "_index", "value": "logs-suricata.alerts-so" } },
|
{
|
||||||
{ "set": { "field": "tags","value": "alert" }},
|
"set": {
|
||||||
{ "rename":{ "field": "message2.alert", "target_field": "rule", "ignore_failure": true } },
|
"if": "ctx.event?.imported != true",
|
||||||
{ "rename":{ "field": "rule.signature", "target_field": "rule.name", "ignore_failure": true } },
|
"field": "_index",
|
||||||
{ "rename":{ "field": "rule.ref", "target_field": "rule.version", "ignore_failure": true } },
|
"value": "logs-suricata.alerts-so"
|
||||||
{ "rename":{ "field": "rule.signature_id", "target_field": "rule.uuid", "ignore_failure": true } },
|
}
|
||||||
{ "rename":{ "field": "rule.signature_id", "target_field": "rule.signature", "ignore_failure": true } },
|
},
|
||||||
{ "rename":{ "field": "message2.payload_printable", "target_field": "network.data.decoded", "ignore_failure": true } },
|
{
|
||||||
{ "dissect": { "field": "rule.rule", "pattern": "%{?prefix}content:\"%{dns.query_name}\"%{?remainder}", "ignore_missing": true, "ignore_failure": true } },
|
"set": {
|
||||||
{ "pipeline": { "name": "common.nids" } }
|
"field": "tags",
|
||||||
]
|
"value": "alert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.alert",
|
||||||
|
"target_field": "rule",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "rule.signature",
|
||||||
|
"target_field": "rule.name",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "rule.ref",
|
||||||
|
"target_field": "rule.version",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "rule.signature_id",
|
||||||
|
"target_field": "rule.uuid",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "rule.signature_id",
|
||||||
|
"target_field": "rule.signature",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.payload_printable",
|
||||||
|
"target_field": "network.data.decoded",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dissect": {
|
||||||
|
"field": "rule.rule",
|
||||||
|
"pattern": "%{?prefix}content:\"%{dns.query_name}\"%{?remainder}",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "common.nids"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,155 @@
|
|||||||
{
|
{
|
||||||
"description" : "suricata.common",
|
"description": "suricata.common",
|
||||||
"processors" : [
|
"processors": [
|
||||||
{ "json": { "field": "message", "target_field": "message2", "ignore_failure": true } },
|
{
|
||||||
{ "rename": { "field": "message2.pkt_src", "target_field": "network.packet_source","ignore_failure": true } },
|
"json": {
|
||||||
{ "rename": { "field": "message2.proto", "target_field": "network.transport", "ignore_failure": true } },
|
"field": "message",
|
||||||
{ "rename": { "field": "message2.in_iface", "target_field": "observer.ingress.interface.name", "ignore_failure": true } },
|
"target_field": "message2",
|
||||||
{ "rename": { "field": "message2.flow_id", "target_field": "log.id.uid", "ignore_failure": true } },
|
"ignore_failure": true
|
||||||
{ "rename": { "field": "message2.src_ip", "target_field": "source.ip", "ignore_failure": true } },
|
}
|
||||||
{ "rename": { "field": "message2.src_port", "target_field": "source.port", "ignore_failure": true } },
|
},
|
||||||
{ "rename": { "field": "message2.dest_ip", "target_field": "destination.ip", "ignore_failure": true } },
|
{
|
||||||
{ "rename": { "field": "message2.dest_port", "target_field": "destination.port", "ignore_failure": true } },
|
"rename": {
|
||||||
{ "rename": { "field": "message2.vlan", "target_field": "network.vlan.id", "ignore_failure": true } },
|
"field": "message2.pkt_src",
|
||||||
{ "rename": { "field": "message2.community_id", "target_field": "network.community_id", "ignore_missing": true } },
|
"target_field": "network.packet_source",
|
||||||
{ "rename": { "field": "message2.xff", "target_field": "xff.ip", "ignore_missing": true } },
|
"ignore_failure": true
|
||||||
{ "set": { "field": "event.dataset", "value": "{{ message2.event_type }}" } },
|
}
|
||||||
{ "set": { "field": "observer.name", "value": "{{agent.name}}" } },
|
},
|
||||||
{ "set": { "field": "event.ingested", "value": "{{@timestamp}}" } },
|
{
|
||||||
{ "date": { "field": "message2.timestamp", "target_field": "@timestamp", "formats": ["ISO8601", "UNIX"], "timezone": "UTC", "ignore_failure": true } },
|
"rename": {
|
||||||
{ "remove":{ "field": "agent", "ignore_failure": true } },
|
"field": "message2.proto",
|
||||||
{"append":{"field":"related.ip","value":["{{source.ip}}","{{destination.ip}}"],"allow_duplicates":false,"ignore_failure":true}},
|
"target_field": "network.transport",
|
||||||
{
|
"ignore_failure": true
|
||||||
"script": {
|
}
|
||||||
"source": "boolean isPrivate(def ip) { if (ip == null) return false; int dot1 = ip.indexOf('.'); if (dot1 == -1) return false; int dot2 = ip.indexOf('.', dot1 + 1); if (dot2 == -1) return false; int first = Integer.parseInt(ip.substring(0, dot1)); if (first == 10) return true; if (first == 192 && ip.startsWith('168.', dot1 + 1)) return true; if (first == 172) { int second = Integer.parseInt(ip.substring(dot1 + 1, dot2)); return second >= 16 && second <= 31; } return false; } String[] fields = new String[] {\"source\", \"destination\"}; for (int i = 0; i < fields.length; i++) { def field = fields[i]; def ip = ctx[field]?.ip; if (ip != null) { if (ctx.network == null) ctx.network = new HashMap(); if (isPrivate(ip)) { if (ctx.network.private_ip == null) ctx.network.private_ip = new ArrayList(); if (!ctx.network.private_ip.contains(ip)) ctx.network.private_ip.add(ip); } else { if (ctx.network.public_ip == null) ctx.network.public_ip = new ArrayList(); if (!ctx.network.public_ip.contains(ip)) ctx.network.public_ip.add(ip); } } }",
|
},
|
||||||
"ignore_failure": false
|
{
|
||||||
}
|
"rename": {
|
||||||
},
|
"field": "message2.in_iface",
|
||||||
{ "pipeline": { "if": "ctx?.event?.dataset != null", "name": "suricata.{{event.dataset}}" } }
|
"target_field": "observer.ingress.interface.name",
|
||||||
]
|
"ignore_failure": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.flow_id",
|
||||||
|
"target_field": "log.id.uid",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.src_ip",
|
||||||
|
"target_field": "source.ip",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.src_port",
|
||||||
|
"target_field": "source.port",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dest_ip",
|
||||||
|
"target_field": "destination.ip",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dest_port",
|
||||||
|
"target_field": "destination.port",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.vlan",
|
||||||
|
"target_field": "network.vlan.id",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.community_id",
|
||||||
|
"target_field": "network.community_id",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.xff",
|
||||||
|
"target_field": "xff.ip",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "event.dataset",
|
||||||
|
"value": "{{ message2.event_type }}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "observer.name",
|
||||||
|
"value": "{{agent.name}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "event.ingested",
|
||||||
|
"value": "{{@timestamp}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": {
|
||||||
|
"field": "message2.timestamp",
|
||||||
|
"target_field": "@timestamp",
|
||||||
|
"formats": [
|
||||||
|
"ISO8601",
|
||||||
|
"UNIX"
|
||||||
|
],
|
||||||
|
"timezone": "UTC",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"remove": {
|
||||||
|
"field": "agent",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"append": {
|
||||||
|
"field": "related.ip",
|
||||||
|
"value": [
|
||||||
|
"{{source.ip}}",
|
||||||
|
"{{destination.ip}}"
|
||||||
|
],
|
||||||
|
"allow_duplicates": false,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "boolean isPrivate(def ip) { if (ip == null) return false; int dot1 = ip.indexOf('.'); if (dot1 == -1) return false; int dot2 = ip.indexOf('.', dot1 + 1); if (dot2 == -1) return false; int first = Integer.parseInt(ip.substring(0, dot1)); if (first == 10) return true; if (first == 192 && ip.startsWith('168.', dot1 + 1)) return true; if (first == 172) { int second = Integer.parseInt(ip.substring(dot1 + 1, dot2)); return second >= 16 && second <= 31; } return false; } String[] fields = new String[] {\"source\", \"destination\"}; for (int i = 0; i < fields.length; i++) { def field = fields[i]; def ip = ctx[field]?.ip; if (ip != null) { if (ctx.network == null) ctx.network = new HashMap(); if (isPrivate(ip)) { if (ctx.network.private_ip == null) ctx.network.private_ip = new ArrayList(); if (!ctx.network.private_ip.contains(ip)) ctx.network.private_ip.add(ip); } else { if (ctx.network.public_ip == null) ctx.network.public_ip = new ArrayList(); if (!ctx.network.public_ip.contains(ip)) ctx.network.public_ip.add(ip); } } }",
|
||||||
|
"ignore_failure": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.capture_file",
|
||||||
|
"target_field": "suricata.capture_file",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"if": "ctx?.event?.dataset != null",
|
||||||
|
"name": "suricata.{{event.dataset}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,21 +1,136 @@
|
|||||||
{
|
{
|
||||||
"description" : "suricata.dns",
|
"description": "suricata.dns",
|
||||||
"processors" : [
|
"processors": [
|
||||||
{ "rename": { "field": "message2.proto", "target_field": "network.transport", "ignore_missing": true } },
|
{
|
||||||
{ "rename": { "field": "message2.app_proto", "target_field": "network.protocol", "ignore_missing": true } },
|
"rename": {
|
||||||
{ "rename": { "field": "message2.dns.type", "target_field": "dns.query.type", "ignore_missing": true } },
|
"field": "message2.proto",
|
||||||
{ "rename": { "field": "message2.dns.tx_id", "target_field": "dns.id", "ignore_missing": true } },
|
"target_field": "network.transport",
|
||||||
{ "rename": { "field": "message2.dns.version", "target_field": "dns.version", "ignore_missing": true } },
|
"ignore_missing": true
|
||||||
{ "rename": { "field": "message2.dns.rrname", "target_field": "dns.query.name", "ignore_missing": true } },
|
}
|
||||||
{ "rename": { "field": "message2.dns.rrtype", "target_field": "dns.query.type_name", "ignore_missing": true } },
|
},
|
||||||
{ "rename": { "field": "message2.dns.flags", "target_field": "dns.flags", "ignore_missing": true } },
|
{
|
||||||
{ "rename": { "field": "message2.dns.qr", "target_field": "dns.qr", "ignore_missing": true } },
|
"rename": {
|
||||||
{ "rename": { "field": "message2.dns.rd", "target_field": "dns.recursion.desired", "ignore_missing": true } },
|
"field": "message2.app_proto",
|
||||||
{ "rename": { "field": "message2.dns.ra", "target_field": "dns.recursion.available", "ignore_missing": true } },
|
"target_field": "network.protocol",
|
||||||
{ "rename": { "field": "message2.dns.rcode", "target_field": "dns.response.code_name", "ignore_missing": true } },
|
"ignore_missing": true
|
||||||
{ "rename": { "field": "message2.dns.grouped.A", "target_field": "dns.answers.data", "ignore_missing": true } },
|
}
|
||||||
{ "rename": { "field": "message2.dns.grouped.CNAME", "target_field": "dns.answers.name", "ignore_missing": true } },
|
},
|
||||||
{ "pipeline": { "if": "ctx.dns.query?.name != null && ctx.dns.query.name.contains('.')", "name": "dns.tld" } },
|
{
|
||||||
{ "pipeline": { "name": "common" } }
|
"rename": {
|
||||||
]
|
"field": "message2.dns.type",
|
||||||
}
|
"target_field": "dns.query.type",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.tx_id",
|
||||||
|
"target_field": "dns.tx_id",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.id",
|
||||||
|
"target_field": "dns.id",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.version",
|
||||||
|
"target_field": "dns.version",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "suricata.dnsv3",
|
||||||
|
"ignore_missing_pipeline": true,
|
||||||
|
"if": "ctx?.dns?.version != null && ctx?.dns?.version == 3",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.rrname",
|
||||||
|
"target_field": "dns.query.name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.rrtype",
|
||||||
|
"target_field": "dns.query.type_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.flags",
|
||||||
|
"target_field": "dns.flags",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.qr",
|
||||||
|
"target_field": "dns.qr",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.rd",
|
||||||
|
"target_field": "dns.recursion.desired",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.ra",
|
||||||
|
"target_field": "dns.recursion.available",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.opcode",
|
||||||
|
"target_field": "dns.opcode",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.rcode",
|
||||||
|
"target_field": "dns.response.code_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.grouped.A",
|
||||||
|
"target_field": "dns.answers.data",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.grouped.CNAME",
|
||||||
|
"target_field": "dns.answers.name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"if": "ctx.dns.query?.name != null && ctx.dns.query.name.contains('.')",
|
||||||
|
"name": "dns.tld"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "common"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
56
salt/elasticsearch/files/ingest/suricata.dnsv3
Normal file
56
salt/elasticsearch/files/ingest/suricata.dnsv3
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"processors": [
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.dns.queries",
|
||||||
|
"target_field": "dns.queries",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx?.dns?.queries != null && ctx?.dns?.queries.length > 0) {\n if (ctx.dns == null) {\n ctx.dns = new HashMap();\n }\n if (ctx.dns.query == null) {\n ctx.dns.query = new HashMap();\n }\n ctx.dns.query.name = ctx?.dns?.queries[0].rrname;\n}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx?.dns?.queries != null && ctx?.dns?.queries.length > 0) {\n if (ctx.dns == null) {\n ctx.dns = new HashMap();\n }\n if (ctx.dns.query == null) {\n ctx.dns.query = new HashMap();\n }\n ctx.dns.query.type_name = ctx?.dns?.queries[0].rrtype;\n}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"foreach": {
|
||||||
|
"field": "dns.queries",
|
||||||
|
"processor": {
|
||||||
|
"rename": {
|
||||||
|
"field": "_ingest._value.rrname",
|
||||||
|
"target_field": "_ingest._value.name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"foreach": {
|
||||||
|
"field": "dns.queries",
|
||||||
|
"processor": {
|
||||||
|
"rename": {
|
||||||
|
"field": "_ingest._value.rrtype",
|
||||||
|
"target_field": "_ingest._value.type_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "suricata.tld",
|
||||||
|
"ignore_missing_pipeline": true,
|
||||||
|
"if": "ctx?.dns?.queries != null && ctx?.dns?.queries.length > 0",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
52
salt/elasticsearch/files/ingest/suricata.tld
Normal file
52
salt/elasticsearch/files/ingest/suricata.tld
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"processors": [
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.name != null && q.name.contains('.')) {\n q.top_level_domain = q.name.substring(q.name.lastIndexOf('.') + 1);\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.name != null && q.name.contains('.')) {\n q.query_without_tld = q.name.substring(0, q.name.lastIndexOf('.'));\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.query_without_tld != null && q.query_without_tld.contains('.')) {\n q.parent_domain = q.query_without_tld.substring(q.query_without_tld.lastIndexOf('.') + 1);\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.query_without_tld != null && q.query_without_tld.contains('.')) {\n q.subdomain = q.query_without_tld.substring(0, q.query_without_tld.lastIndexOf('.'));\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.parent_domain != null && q.top_level_domain != null) {\n q.highest_registered_domain = q.parent_domain + \".\" + q.top_level_domain;\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.subdomain != null) {\n q.subdomain_length = q.subdomain.length();\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n if (q.parent_domain != null) {\n q.parent_domain_length = q.parent_domain.length();\n }\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns != null && ctx.dns.queries != null) {\n for (def q : ctx.dns.queries) {\n q.remove('query_without_tld');\n }\n}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
61
salt/elasticsearch/files/ingest/zeek.analyzer
Normal file
61
salt/elasticsearch/files/ingest/zeek.analyzer
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"description": "zeek.analyzer",
|
||||||
|
"processors": [
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "event.dataset",
|
||||||
|
"value": "analyzer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"remove": {
|
||||||
|
"field": [
|
||||||
|
"host"
|
||||||
|
],
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"field": "message",
|
||||||
|
"target_field": "message2",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "network.protocol",
|
||||||
|
"copy_from": "message2.analyzer_name",
|
||||||
|
"ignore_empty_value": true,
|
||||||
|
"if": "ctx?.message2?.analyzer_kind == 'protocol'"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"field": "network.protocol",
|
||||||
|
"ignore_empty_value": true,
|
||||||
|
"if": "ctx?.message2?.analyzer_kind != 'protocol'",
|
||||||
|
"copy_from": "message2.proto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lowercase": {
|
||||||
|
"field": "network.protocol",
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.failure_reason",
|
||||||
|
"target_field": "error.reason",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "zeek.common"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,35 +1,227 @@
|
|||||||
{
|
{
|
||||||
"description" : "zeek.dns",
|
"description": "zeek.dns",
|
||||||
"processors" : [
|
"processors": [
|
||||||
{ "set": { "field": "event.dataset", "value": "dns" } },
|
{
|
||||||
{ "remove": { "field": ["host"], "ignore_failure": true } },
|
"set": {
|
||||||
{ "json": { "field": "message", "target_field": "message2", "ignore_failure": true } },
|
"field": "event.dataset",
|
||||||
{ "dot_expander": { "field": "id.orig_h", "path": "message2", "ignore_failure": true } },
|
"value": "dns"
|
||||||
{ "rename": { "field": "message2.proto", "target_field": "network.transport", "ignore_missing": true } },
|
}
|
||||||
{ "rename": { "field": "message2.trans_id", "target_field": "dns.id", "ignore_missing": true } },
|
},
|
||||||
{ "rename": { "field": "message2.rtt", "target_field": "event.duration", "ignore_missing": true } },
|
{
|
||||||
{ "rename": { "field": "message2.query", "target_field": "dns.query.name", "ignore_missing": true } },
|
"remove": {
|
||||||
{ "rename": { "field": "message2.qclass", "target_field": "dns.query.class", "ignore_missing": true } },
|
"field": [
|
||||||
{ "rename": { "field": "message2.qclass_name", "target_field": "dns.query.class_name", "ignore_missing": true } },
|
"host"
|
||||||
{ "rename": { "field": "message2.qtype", "target_field": "dns.query.type", "ignore_missing": true } },
|
],
|
||||||
{ "rename": { "field": "message2.qtype_name", "target_field": "dns.query.type_name", "ignore_missing": true } },
|
"ignore_failure": true
|
||||||
{ "rename": { "field": "message2.rcode", "target_field": "dns.response.code", "ignore_missing": true } },
|
}
|
||||||
{ "rename": { "field": "message2.rcode_name", "target_field": "dns.response.code_name", "ignore_missing": true } },
|
},
|
||||||
{ "rename": { "field": "message2.AA", "target_field": "dns.authoritative", "ignore_missing": true } },
|
{
|
||||||
{ "rename": { "field": "message2.TC", "target_field": "dns.truncated", "ignore_missing": true } },
|
"json": {
|
||||||
{ "rename": { "field": "message2.RD", "target_field": "dns.recursion.desired", "ignore_missing": true } },
|
"field": "message",
|
||||||
{ "rename": { "field": "message2.RA", "target_field": "dns.recursion.available", "ignore_missing": true } },
|
"target_field": "message2",
|
||||||
{ "rename": { "field": "message2.Z", "target_field": "dns.reserved", "ignore_missing": true } },
|
"ignore_failure": true
|
||||||
{ "rename": { "field": "message2.answers", "target_field": "dns.answers.name", "ignore_missing": true } },
|
}
|
||||||
{ "foreach": {"field": "dns.answers.name","processor": {"pipeline": {"name": "common.ip_validation"}},"if": "ctx.dns != null && ctx.dns.answers != null && ctx.dns.answers.name != null","ignore_failure": true}},
|
},
|
||||||
{ "foreach": {"field": "temp._valid_ips","processor": {"append": {"field": "dns.resolved_ip","allow_duplicates": false,"value": "{{{_ingest._value}}}","ignore_failure": true}},"ignore_failure": true}},
|
{
|
||||||
{ "script": { "source": "if (ctx.dns.resolved_ip != null && ctx.dns.resolved_ip instanceof List) {\n ctx.dns.resolved_ip.removeIf(item -> item == null || item.toString().trim().isEmpty());\n }","ignore_failure": true }},
|
"dot_expander": {
|
||||||
{ "remove": {"field": ["temp"], "ignore_missing": true ,"ignore_failure": true } },
|
"field": "id.orig_h",
|
||||||
{ "rename": { "field": "message2.TTLs", "target_field": "dns.ttls", "ignore_missing": true } },
|
"path": "message2",
|
||||||
{ "rename": { "field": "message2.rejected", "target_field": "dns.query.rejected", "ignore_missing": true } },
|
"ignore_failure": true
|
||||||
{ "script": { "lang": "painless", "source": "ctx.dns.query.length = ctx.dns.query.name.length()", "ignore_failure": true } },
|
}
|
||||||
{ "set": { "if": "ctx._index == 'so-zeek'", "field": "_index", "value": "so-zeek_dns", "override": true } },
|
},
|
||||||
{ "pipeline": { "if": "ctx.dns?.query?.name != null && ctx.dns.query.name.contains('.')", "name": "dns.tld" } },
|
{
|
||||||
{ "pipeline": { "name": "zeek.common" } }
|
"rename": {
|
||||||
]
|
"field": "message2.proto",
|
||||||
|
"target_field": "network.transport",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.trans_id",
|
||||||
|
"target_field": "dns.id",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.rtt",
|
||||||
|
"target_field": "event.duration",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.query",
|
||||||
|
"target_field": "dns.query.name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.qclass",
|
||||||
|
"target_field": "dns.query.class",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.qclass_name",
|
||||||
|
"target_field": "dns.query.class_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.qtype",
|
||||||
|
"target_field": "dns.query.type",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.qtype_name",
|
||||||
|
"target_field": "dns.query.type_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.rcode",
|
||||||
|
"target_field": "dns.response.code",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.rcode_name",
|
||||||
|
"target_field": "dns.response.code_name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.AA",
|
||||||
|
"target_field": "dns.authoritative",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.TC",
|
||||||
|
"target_field": "dns.truncated",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.RD",
|
||||||
|
"target_field": "dns.recursion.desired",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.RA",
|
||||||
|
"target_field": "dns.recursion.available",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.Z",
|
||||||
|
"target_field": "dns.reserved",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.answers",
|
||||||
|
"target_field": "dns.answers.name",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"foreach": {
|
||||||
|
"field": "dns.answers.name",
|
||||||
|
"processor": {
|
||||||
|
"pipeline": {
|
||||||
|
"name": "common.ip_validation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"if": "ctx.dns != null && ctx.dns.answers != null && ctx.dns.answers.name != null",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"foreach": {
|
||||||
|
"field": "temp._valid_ips",
|
||||||
|
"processor": {
|
||||||
|
"append": {
|
||||||
|
"field": "dns.resolved_ip",
|
||||||
|
"allow_duplicates": false,
|
||||||
|
"value": "{{{_ingest._value}}}",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"if": "ctx.dns != null && ctx.dns.answers != null && ctx.dns.answers.name != null",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"source": "if (ctx.dns.resolved_ip != null && ctx.dns.resolved_ip instanceof List) {\n ctx.dns.resolved_ip.removeIf(item -> item == null || item.toString().trim().isEmpty());\n }",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"remove": {
|
||||||
|
"field": [
|
||||||
|
"temp"
|
||||||
|
],
|
||||||
|
"ignore_missing": true,
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.TTLs",
|
||||||
|
"target_field": "dns.ttls",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rename": {
|
||||||
|
"field": "message2.rejected",
|
||||||
|
"target_field": "dns.query.rejected",
|
||||||
|
"ignore_missing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"lang": "painless",
|
||||||
|
"source": "ctx.dns.query.length = ctx.dns.query.name.length()",
|
||||||
|
"ignore_failure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set": {
|
||||||
|
"if": "ctx._index == 'so-zeek'",
|
||||||
|
"field": "_index",
|
||||||
|
"value": "so-zeek_dns",
|
||||||
|
"override": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"if": "ctx.dns?.query?.name != null && ctx.dns.query.name.contains('.')",
|
||||||
|
"name": "dns.tld"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pipeline": {
|
||||||
|
"name": "zeek.common"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"description" : "zeek.dpd",
|
|
||||||
"processors" : [
|
|
||||||
{ "set": { "field": "event.dataset", "value": "dpd" } },
|
|
||||||
{ "remove": { "field": ["host"], "ignore_failure": true } },
|
|
||||||
{ "json": { "field": "message", "target_field": "message2", "ignore_failure": true } },
|
|
||||||
{ "dot_expander": { "field": "id.orig_h", "path": "message2", "ignore_failure": true } },
|
|
||||||
{ "rename": { "field": "message2.id.orig_h", "target_field": "source.ip", "ignore_missing": true } },
|
|
||||||
{ "dot_expander": { "field": "id.orig_p", "path": "message2", "ignore_failure": true } },
|
|
||||||
{ "rename": { "field": "message2.id.orig_p", "target_field": "source.port", "ignore_missing": true } },
|
|
||||||
{ "dot_expander": { "field": "id.resp_h", "path": "message2", "ignore_failure": true } },
|
|
||||||
{ "rename": { "field": "message2.id.resp_h", "target_field": "destination.ip", "ignore_missing": true } },
|
|
||||||
{ "dot_expander": { "field": "id.resp_p", "path": "message2", "ignore_failure": true } },
|
|
||||||
{ "rename": { "field": "message2.id.resp_p", "target_field": "destination.port", "ignore_missing": true } },
|
|
||||||
{ "rename": { "field": "message2.proto", "target_field": "network.protocol", "ignore_missing": true } },
|
|
||||||
{ "rename": { "field": "message2.analyzer", "target_field": "observer.analyzer", "ignore_missing": true } },
|
|
||||||
{ "rename": { "field": "message2.failure_reason", "target_field": "error.reason", "ignore_missing": true } },
|
|
||||||
{ "pipeline": { "name": "zeek.common" } }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -131,6 +131,47 @@ elasticsearch:
|
|||||||
description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index.
|
description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index.
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
forcedType: string
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
cold:
|
cold:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
||||||
@@ -144,6 +185,12 @@ elasticsearch:
|
|||||||
description: Used for index recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities.
|
description: Used for index recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities.
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
warm:
|
warm:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
||||||
@@ -158,6 +205,52 @@ elasticsearch:
|
|||||||
forcedType: int
|
forcedType: int
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
delete:
|
delete:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
||||||
@@ -287,6 +380,47 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
forcedType: string
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
warm:
|
warm:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
||||||
@@ -314,6 +448,52 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
cold:
|
cold:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
||||||
@@ -330,6 +510,12 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
delete:
|
delete:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
||||||
|
|||||||
@@ -61,5 +61,55 @@
|
|||||||
{% do settings.index_template.template.settings.index.pop('sort') %}
|
{% do settings.index_template.template.settings.index.pop('sort') %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{# advanced ilm actions #}
|
||||||
|
{% if settings.policy is defined and settings.policy.phases is defined %}
|
||||||
|
{% set PHASE_NAMES = ["hot", "warm", "cold"] %}
|
||||||
|
{% for P in PHASE_NAMES %}
|
||||||
|
{% if settings.policy.phases[P] is defined and settings.policy.phases[P].actions is defined %}
|
||||||
|
{% set PHASE = settings.policy.phases[P].actions %}
|
||||||
|
{# remove allocate action if number_of_replicas isn't configured #}
|
||||||
|
{% if PHASE.allocate is defined %}
|
||||||
|
{% if PHASE.allocate.number_of_replicas is not defined or PHASE.allocate.number_of_replicas == "" %}
|
||||||
|
{% do PHASE.pop('allocate', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# start shrink action #}
|
||||||
|
{% if PHASE.shrink is defined %}
|
||||||
|
{% if PHASE.shrink.method is defined %}
|
||||||
|
{% if PHASE.shrink.method == 'COUNT' and PHASE.shrink.number_of_shards is defined and PHASE.shrink.number_of_shards %}
|
||||||
|
{# remove max_primary_shard_size value when doing shrink operation by count vs size #}
|
||||||
|
{% do PHASE.shrink.pop('max_primary_shard_size', none) %}
|
||||||
|
{% elif PHASE.shrink.method == 'SIZE' and PHASE.shrink.max_primary_shard_size is defined and PHASE.shrink.max_primary_shard_size %}
|
||||||
|
{# remove number_of_shards value when doing shrink operation by size vs count #}
|
||||||
|
{% do PHASE.shrink.pop('number_of_shards', none) %}
|
||||||
|
{% else %}
|
||||||
|
{# method isn't defined or missing a required config number_of_shards/max_primary_shard_size #}
|
||||||
|
{% do PHASE.pop('shrink', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# always remove shrink method since its only used for SOC config, not in the actual ilm policy #}
|
||||||
|
{% if PHASE.shrink is defined %}
|
||||||
|
{% do PHASE.shrink.pop('method', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{# end shrink action #}
|
||||||
|
{# start force merge #}
|
||||||
|
{% if PHASE.forcemerge is defined %}
|
||||||
|
{% if PHASE.forcemerge.index_codec is defined and PHASE.forcemerge.index_codec %}
|
||||||
|
{% do PHASE.forcemerge.update({'index_codec': 'best_compression'}) %}
|
||||||
|
{% else %}
|
||||||
|
{% do PHASE.forcemerge.pop('index_codec', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% if PHASE.forcemerge.max_num_segments is not defined or not PHASE.forcemerge.max_num_segments %}
|
||||||
|
{# max_num_segments is empty, drop it #}
|
||||||
|
{% do PHASE.pop('forcemerge', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# end force merge #}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% do ES_INDEX_SETTINGS.update({index | replace("_x_", "."): ES_INDEX_SETTINGS_GLOBAL_OVERRIDES[index]}) %}
|
{% do ES_INDEX_SETTINGS.update({index | replace("_x_", "."): ES_INDEX_SETTINGS_GLOBAL_OVERRIDES[index]}) %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -841,6 +841,10 @@
|
|||||||
"type": "long"
|
"type": "long"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"capture_file": {
|
||||||
|
"type": "keyword",
|
||||||
|
"ignore_above": 1024
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1164
salt/elasticsearch/tools/sbin/so-elasticsearch-retention-estimate
Executable file
1164
salt/elasticsearch/tools/sbin/so-elasticsearch-retention-estimate
Executable file
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ used during VM provisioning to add dedicated NSM storage volumes.
|
|||||||
This command creates and attaches a volume with the following settings:
|
This command creates and attaches a volume with the following settings:
|
||||||
- VM Name: `vm1_sensor`
|
- VM Name: `vm1_sensor`
|
||||||
- Volume Size: `500` GB
|
- Volume Size: `500` GB
|
||||||
- Volume Path: `/nsm/libvirt/volumes/vm1_sensor-nsm.img`
|
- Volume Path: `/nsm/libvirt/volumes/vm1_sensor-nsm-<epoch_timestamp>.img`
|
||||||
- Device: `/dev/vdb` (virtio-blk)
|
- Device: `/dev/vdb` (virtio-blk)
|
||||||
- VM remains stopped after attachment
|
- VM remains stopped after attachment
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ used during VM provisioning to add dedicated NSM storage volumes.
|
|||||||
|
|
||||||
- The script automatically stops the VM if it's running before creating and attaching the volume.
|
- The script automatically stops the VM if it's running before creating and attaching the volume.
|
||||||
- Volumes are created with full pre-allocation for optimal performance.
|
- Volumes are created with full pre-allocation for optimal performance.
|
||||||
- Volume files are stored in `/nsm/libvirt/volumes/` with naming pattern `<vm_name>-nsm.img`.
|
- Volume files are stored in `/nsm/libvirt/volumes/` with naming pattern `<vm_name>-nsm-<epoch_timestamp>.img`.
|
||||||
|
- The epoch timestamp ensures unique volume names and prevents conflicts.
|
||||||
- Volumes are attached as `/dev/vdb` using virtio-blk for high performance.
|
- Volumes are attached as `/dev/vdb` using virtio-blk for high performance.
|
||||||
- The script checks available disk space before creating the volume.
|
- The script checks available disk space before creating the volume.
|
||||||
- Ownership is set to `qemu:qemu` with permissions `640`.
|
- Ownership is set to `qemu:qemu` with permissions `640`.
|
||||||
@@ -142,6 +143,7 @@ import socket
|
|||||||
import subprocess
|
import subprocess
|
||||||
import pwd
|
import pwd
|
||||||
import grp
|
import grp
|
||||||
|
import time
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from so_vm_utils import start_vm, stop_vm
|
from so_vm_utils import start_vm, stop_vm
|
||||||
@@ -242,10 +244,13 @@ def create_volume_file(vm_name, size_gb, logger):
|
|||||||
Raises:
|
Raises:
|
||||||
VolumeCreationError: If volume creation fails
|
VolumeCreationError: If volume creation fails
|
||||||
"""
|
"""
|
||||||
# Define volume path (directory already created in main())
|
# Generate epoch timestamp for unique volume naming
|
||||||
volume_path = os.path.join(VOLUME_DIR, f"{vm_name}-nsm.img")
|
epoch_timestamp = int(time.time())
|
||||||
|
|
||||||
# Check if volume already exists
|
# Define volume path with epoch timestamp for uniqueness
|
||||||
|
volume_path = os.path.join(VOLUME_DIR, f"{vm_name}-nsm-{epoch_timestamp}.img")
|
||||||
|
|
||||||
|
# Check if volume already exists (shouldn't be possible with timestamp)
|
||||||
if os.path.exists(volume_path):
|
if os.path.exists(volume_path):
|
||||||
logger.error(f"VOLUME: Volume already exists: {volume_path}")
|
logger.error(f"VOLUME: Volume already exists: {volume_path}")
|
||||||
raise VolumeCreationError(f"Volume already exists: {volume_path}")
|
raise VolumeCreationError(f"Volume already exists: {volume_path}")
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
|
||||||
{% if sls.split('.')[0] in allowed_states %}
|
|
||||||
|
|
||||||
include:
|
|
||||||
- idstools.sync_files
|
|
||||||
|
|
||||||
idstoolslogdir:
|
|
||||||
file.directory:
|
|
||||||
- name: /opt/so/log/idstools
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- makedirs: True
|
|
||||||
|
|
||||||
idstools_sbin:
|
|
||||||
file.recurse:
|
|
||||||
- name: /usr/sbin
|
|
||||||
- source: salt://idstools/tools/sbin
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- file_mode: 755
|
|
||||||
|
|
||||||
# If this is used, exclude so-rule-update
|
|
||||||
#idstools_sbin_jinja:
|
|
||||||
# file.recurse:
|
|
||||||
# - name: /usr/sbin
|
|
||||||
# - source: salt://idstools/tools/sbin_jinja
|
|
||||||
# - user: 939
|
|
||||||
# - group: 939
|
|
||||||
# - file_mode: 755
|
|
||||||
# - template: jinja
|
|
||||||
|
|
||||||
idstools_so-rule-update:
|
|
||||||
file.managed:
|
|
||||||
- name: /usr/sbin/so-rule-update
|
|
||||||
- source: salt://idstools/tools/sbin_jinja/so-rule-update
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- mode: 755
|
|
||||||
- template: jinja
|
|
||||||
|
|
||||||
suricatacustomdirsfile:
|
|
||||||
file.directory:
|
|
||||||
- name: /nsm/rules/detect-suricata/custom_file
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- makedirs: True
|
|
||||||
|
|
||||||
suricatacustomdirsurl:
|
|
||||||
file.directory:
|
|
||||||
- name: /nsm/rules/detect-suricata/custom_temp
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
|
||||||
test.fail_without_changes:
|
|
||||||
- name: {{sls}}_state_not_allowed
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
idstools:
|
|
||||||
enabled: False
|
|
||||||
config:
|
|
||||||
urls: []
|
|
||||||
ruleset: ETOPEN
|
|
||||||
oinkcode: ""
|
|
||||||
sids:
|
|
||||||
enabled: []
|
|
||||||
disabled: []
|
|
||||||
modify: []
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
|
||||||
{% if sls.split('.')[0] in allowed_states %}
|
|
||||||
|
|
||||||
include:
|
|
||||||
- idstools.sostatus
|
|
||||||
|
|
||||||
so-idstools:
|
|
||||||
docker_container.absent:
|
|
||||||
- force: True
|
|
||||||
|
|
||||||
so-idstools_so-status.disabled:
|
|
||||||
file.comment:
|
|
||||||
- name: /opt/so/conf/so-status/so-status.conf
|
|
||||||
- regex: ^so-idstools$
|
|
||||||
|
|
||||||
so-rule-update:
|
|
||||||
cron.absent:
|
|
||||||
- identifier: so-rule-update
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
|
||||||
test.fail_without_changes:
|
|
||||||
- name: {{sls}}_state_not_allowed
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
|
||||||
{% if sls.split('.')[0] in allowed_states %}
|
|
||||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
|
||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
|
||||||
{% set proxy = salt['pillar.get']('manager:proxy') %}
|
|
||||||
|
|
||||||
include:
|
|
||||||
- idstools.config
|
|
||||||
- idstools.sostatus
|
|
||||||
|
|
||||||
so-idstools:
|
|
||||||
docker_container.running:
|
|
||||||
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-idstools:{{ GLOBALS.so_version }}
|
|
||||||
- hostname: so-idstools
|
|
||||||
- user: socore
|
|
||||||
- networks:
|
|
||||||
- sobridge:
|
|
||||||
- ipv4_address: {{ DOCKER.containers['so-idstools'].ip }}
|
|
||||||
{% if proxy %}
|
|
||||||
- environment:
|
|
||||||
- http_proxy={{ proxy }}
|
|
||||||
- https_proxy={{ proxy }}
|
|
||||||
- no_proxy={{ salt['pillar.get']('manager:no_proxy') }}
|
|
||||||
{% if DOCKER.containers['so-idstools'].extra_env %}
|
|
||||||
{% for XTRAENV in DOCKER.containers['so-idstools'].extra_env %}
|
|
||||||
- {{ XTRAENV }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% elif DOCKER.containers['so-idstools'].extra_env %}
|
|
||||||
- environment:
|
|
||||||
{% for XTRAENV in DOCKER.containers['so-idstools'].extra_env %}
|
|
||||||
- {{ XTRAENV }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
- binds:
|
|
||||||
- /opt/so/conf/idstools/etc:/opt/so/idstools/etc:ro
|
|
||||||
- /opt/so/rules/nids/suri:/opt/so/rules/nids/suri:rw
|
|
||||||
- /nsm/rules/:/nsm/rules/:rw
|
|
||||||
{% if DOCKER.containers['so-idstools'].custom_bind_mounts %}
|
|
||||||
{% for BIND in DOCKER.containers['so-idstools'].custom_bind_mounts %}
|
|
||||||
- {{ BIND }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
- extra_hosts:
|
|
||||||
- {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }}
|
|
||||||
{% if DOCKER.containers['so-idstools'].extra_hosts %}
|
|
||||||
{% for XTRAHOST in DOCKER.containers['so-idstools'].extra_hosts %}
|
|
||||||
- {{ XTRAHOST }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
- watch:
|
|
||||||
- file: idstoolsetcsync
|
|
||||||
- file: idstools_so-rule-update
|
|
||||||
|
|
||||||
delete_so-idstools_so-status.disabled:
|
|
||||||
file.uncomment:
|
|
||||||
- name: /opt/so/conf/so-status/so-status.conf
|
|
||||||
- regex: ^so-idstools$
|
|
||||||
|
|
||||||
so-rule-update:
|
|
||||||
cron.present:
|
|
||||||
- name: /usr/sbin/so-rule-update > /opt/so/log/idstools/download_cron.log 2>&1
|
|
||||||
- identifier: so-rule-update
|
|
||||||
- user: root
|
|
||||||
- minute: '1'
|
|
||||||
- hour: '7'
|
|
||||||
|
|
||||||
# order this last to give so-idstools container time to be ready
|
|
||||||
run_so-rule-update:
|
|
||||||
cmd.run:
|
|
||||||
- name: '/usr/sbin/so-rule-update > /opt/so/log/idstools/download_idstools_state.log 2>&1'
|
|
||||||
- require:
|
|
||||||
- docker_container: so-idstools
|
|
||||||
- onchanges:
|
|
||||||
- file: idstools_so-rule-update
|
|
||||||
- file: idstoolsetcsync
|
|
||||||
- file: synclocalnidsrules
|
|
||||||
- order: last
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
|
||||||
test.fail_without_changes:
|
|
||||||
- name: {{sls}}_state_not_allowed
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{%- set disabled_sids = salt['pillar.get']('idstools:sids:disabled', {}) -%}
|
|
||||||
# idstools - disable.conf
|
|
||||||
|
|
||||||
# Example of disabling a rule by signature ID (gid is optional).
|
|
||||||
# 1:2019401
|
|
||||||
# 2019401
|
|
||||||
|
|
||||||
# Example of disabling a rule by regular expression.
|
|
||||||
# - All regular expression matches are case insensitive.
|
|
||||||
# re:hearbleed
|
|
||||||
# re:MS(0[7-9]|10)-\d+
|
|
||||||
{%- if disabled_sids != None %}
|
|
||||||
{%- for sid in disabled_sids %}
|
|
||||||
{{ sid }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{%- set enabled_sids = salt['pillar.get']('idstools:sids:enabled', {}) -%}
|
|
||||||
# idstools-rulecat - enable.conf
|
|
||||||
|
|
||||||
# Example of enabling a rule by signature ID (gid is optional).
|
|
||||||
# 1:2019401
|
|
||||||
# 2019401
|
|
||||||
|
|
||||||
# Example of enabling a rule by regular expression.
|
|
||||||
# - All regular expression matches are case insensitive.
|
|
||||||
# re:hearbleed
|
|
||||||
# re:MS(0[7-9]|10)-\d+
|
|
||||||
{%- if enabled_sids != None %}
|
|
||||||
{%- for sid in enabled_sids %}
|
|
||||||
{{ sid }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{%- set modify_sids = salt['pillar.get']('idstools:sids:modify', {}) -%}
|
|
||||||
# idstools-rulecat - modify.conf
|
|
||||||
|
|
||||||
# Format: <sid> "<from>" "<to>"
|
|
||||||
|
|
||||||
# Example changing the seconds for rule 2019401 to 3600.
|
|
||||||
#2019401 "seconds \d+" "seconds 3600"
|
|
||||||
{%- if modify_sids != None %}
|
|
||||||
{%- for sid in modify_sids %}
|
|
||||||
{{ sid }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{%- from 'vars/globals.map.jinja' import GLOBALS -%}
|
|
||||||
{%- from 'soc/merged.map.jinja' import SOCMERGED -%}
|
|
||||||
--suricata-version=7.0.3
|
|
||||||
--merged=/opt/so/rules/nids/suri/all.rules
|
|
||||||
--output=/nsm/rules/detect-suricata/custom_temp
|
|
||||||
--local=/opt/so/rules/nids/suri/local.rules
|
|
||||||
{%- if GLOBALS.md_engine == "SURICATA" %}
|
|
||||||
--local=/opt/so/rules/nids/suri/extraction.rules
|
|
||||||
--local=/opt/so/rules/nids/suri/filters.rules
|
|
||||||
{%- endif %}
|
|
||||||
--url=http://{{ GLOBALS.manager }}:7788/suricata/emerging-all.rules
|
|
||||||
--disable=/opt/so/idstools/etc/disable.conf
|
|
||||||
--enable=/opt/so/idstools/etc/enable.conf
|
|
||||||
--modify=/opt/so/idstools/etc/modify.conf
|
|
||||||
{%- if SOCMERGED.config.server.modules.suricataengine.customRulesets %}
|
|
||||||
{%- for ruleset in SOCMERGED.config.server.modules.suricataengine.customRulesets %}
|
|
||||||
{%- if 'url' in ruleset %}
|
|
||||||
--url={{ ruleset.url }}
|
|
||||||
{%- elif 'file' in ruleset %}
|
|
||||||
--local={{ ruleset.file }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
{% from 'idstools/map.jinja' import IDSTOOLSMERGED %}
|
|
||||||
|
|
||||||
include:
|
|
||||||
{% if IDSTOOLSMERGED.enabled %}
|
|
||||||
- idstools.enabled
|
|
||||||
{% else %}
|
|
||||||
- idstools.disabled
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
Elastic License 2.0. #}
|
|
||||||
|
|
||||||
{% import_yaml 'idstools/defaults.yaml' as IDSTOOLSDEFAULTS with context %}
|
|
||||||
{% set IDSTOOLSMERGED = salt['pillar.get']('idstools', IDSTOOLSDEFAULTS.idstools, merge=True) %}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
# Add your custom Suricata rules in this file.
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
idstools:
|
|
||||||
enabled:
|
|
||||||
description: Enables or disables the IDStools process which is used by the Detection system.
|
|
||||||
config:
|
|
||||||
oinkcode:
|
|
||||||
description: Enter your registration code or oinkcode for paid NIDS rulesets.
|
|
||||||
title: Registration Code
|
|
||||||
global: True
|
|
||||||
forcedType: string
|
|
||||||
helpLink: rules.html
|
|
||||||
ruleset:
|
|
||||||
description: 'Defines the ruleset you want to run. Options are ETOPEN or ETPRO. Once you have changed the ruleset here, you will need to wait for the rule update to take place (every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Suricata --> Full Update. WARNING! Changing the ruleset will remove all existing non-overlapping Suricata rules of the previous ruleset and their associated overrides. This removal cannot be undone.'
|
|
||||||
global: True
|
|
||||||
regex: ETPRO\b|ETOPEN\b
|
|
||||||
helpLink: rules.html
|
|
||||||
urls:
|
|
||||||
description: This is a list of additional rule download locations. This feature is currently disabled.
|
|
||||||
global: True
|
|
||||||
multiline: True
|
|
||||||
forcedType: "[]string"
|
|
||||||
readonly: True
|
|
||||||
helpLink: rules.html
|
|
||||||
sids:
|
|
||||||
disabled:
|
|
||||||
description: Contains the list of NIDS rules (or regex patterns) disabled across the grid. This setting is readonly; Use the Detections screen to disable rules.
|
|
||||||
global: True
|
|
||||||
multiline: True
|
|
||||||
forcedType: "[]string"
|
|
||||||
regex: \d*|re:.*
|
|
||||||
helpLink: managing-alerts.html
|
|
||||||
readonlyUi: True
|
|
||||||
advanced: true
|
|
||||||
enabled:
|
|
||||||
description: Contains the list of NIDS rules (or regex patterns) enabled across the grid. This setting is readonly; Use the Detections screen to enable rules.
|
|
||||||
global: True
|
|
||||||
multiline: True
|
|
||||||
forcedType: "[]string"
|
|
||||||
regex: \d*|re:.*
|
|
||||||
helpLink: managing-alerts.html
|
|
||||||
readonlyUi: True
|
|
||||||
advanced: true
|
|
||||||
modify:
|
|
||||||
description: Contains the list of NIDS rules (SID "REGEX_SEARCH_TERM" "REGEX_REPLACE_TERM"). This setting is readonly; Use the Detections screen to modify rules.
|
|
||||||
global: True
|
|
||||||
multiline: True
|
|
||||||
forcedType: "[]string"
|
|
||||||
helpLink: managing-alerts.html
|
|
||||||
readonlyUi: True
|
|
||||||
advanced: true
|
|
||||||
rules:
|
|
||||||
local__rules:
|
|
||||||
description: Contains the list of custom NIDS rules applied to the grid. This setting is readonly; Use the Detections screen to adjust rules.
|
|
||||||
file: True
|
|
||||||
global: True
|
|
||||||
advanced: True
|
|
||||||
title: Local Rules
|
|
||||||
helpLink: local-rules.html
|
|
||||||
readonlyUi: True
|
|
||||||
filters__rules:
|
|
||||||
description: If you are using Suricata for metadata, then you can set custom filters for that metadata here.
|
|
||||||
file: True
|
|
||||||
global: True
|
|
||||||
advanced: True
|
|
||||||
title: Filter Rules
|
|
||||||
helpLink: suricata.html
|
|
||||||
extraction__rules:
|
|
||||||
description: If you are using Suricata for metadata, then you can set a list of MIME types for file extraction here.
|
|
||||||
file: True
|
|
||||||
global: True
|
|
||||||
advanced: True
|
|
||||||
title: Extraction Rules
|
|
||||||
helpLink: suricata.html
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
|
||||||
{% if sls.split('.')[0] in allowed_states %}
|
|
||||||
|
|
||||||
append_so-idstools_so-status.conf:
|
|
||||||
file.append:
|
|
||||||
- name: /opt/so/conf/so-status/so-status.conf
|
|
||||||
- text: so-idstools
|
|
||||||
- unless: grep -q so-idstools /opt/so/conf/so-status/so-status.conf
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
|
||||||
test.fail_without_changes:
|
|
||||||
- name: {{sls}}_state_not_allowed
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
|
|
||||||
idstoolsdir:
|
|
||||||
file.directory:
|
|
||||||
- name: /opt/so/conf/idstools/etc
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- makedirs: True
|
|
||||||
|
|
||||||
idstoolsetcsync:
|
|
||||||
file.recurse:
|
|
||||||
- name: /opt/so/conf/idstools/etc
|
|
||||||
- source: salt://idstools/etc
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- template: jinja
|
|
||||||
|
|
||||||
rulesdir:
|
|
||||||
file.directory:
|
|
||||||
- name: /opt/so/rules/nids/suri
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- makedirs: True
|
|
||||||
|
|
||||||
# Don't show changes because all.rules can be large
|
|
||||||
synclocalnidsrules:
|
|
||||||
file.recurse:
|
|
||||||
- name: /opt/so/rules/nids/suri/
|
|
||||||
- source: salt://idstools/rules/
|
|
||||||
- user: 939
|
|
||||||
- group: 939
|
|
||||||
- show_changes: False
|
|
||||||
- include_pat: 'E@.rules'
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
|
||||||
|
|
||||||
/usr/sbin/so-restart idstools $1
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
|
||||||
|
|
||||||
/usr/sbin/so-start idstools $1
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
|
||||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
|
||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
|
||||||
# Elastic License 2.0.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
|
||||||
|
|
||||||
/usr/sbin/so-stop idstools $1
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# if this script isn't already running
|
|
||||||
if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then
|
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
|
||||||
|
|
||||||
{%- from 'vars/globals.map.jinja' import GLOBALS %}
|
|
||||||
{%- from 'idstools/map.jinja' import IDSTOOLSMERGED %}
|
|
||||||
|
|
||||||
{%- set proxy = salt['pillar.get']('manager:proxy') %}
|
|
||||||
{%- set noproxy = salt['pillar.get']('manager:no_proxy', '') %}
|
|
||||||
|
|
||||||
{%- if proxy %}
|
|
||||||
# Download the rules from the internet
|
|
||||||
export http_proxy={{ proxy }}
|
|
||||||
export https_proxy={{ proxy }}
|
|
||||||
export no_proxy="{{ noproxy }}"
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
mkdir -p /nsm/rules/suricata
|
|
||||||
chown -R socore:socore /nsm/rules/suricata
|
|
||||||
{%- if not GLOBALS.airgap %}
|
|
||||||
# Download the rules from the internet
|
|
||||||
{%- if IDSTOOLSMERGED.config.ruleset == 'ETOPEN' %}
|
|
||||||
docker exec so-idstools idstools-rulecat -v --suricata-version 7.0.3 -o /nsm/rules/suricata/ --merged=/nsm/rules/suricata/emerging-all.rules --force
|
|
||||||
{%- elif IDSTOOLSMERGED.config.ruleset == 'ETPRO' %}
|
|
||||||
docker exec so-idstools idstools-rulecat -v --suricata-version 7.0.3 -o /nsm/rules/suricata/ --merged=/nsm/rules/suricata/emerging-all.rules --force --etpro={{ IDSTOOLSMERGED.config.oinkcode }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
|
|
||||||
argstr=""
|
|
||||||
for arg in "$@"; do
|
|
||||||
argstr="${argstr} \"${arg}\""
|
|
||||||
done
|
|
||||||
|
|
||||||
docker exec so-idstools /bin/bash -c "cd /opt/so/idstools/etc && idstools-rulecat --force ${argstr}"
|
|
||||||
|
|
||||||
fi
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -31,6 +31,19 @@ libvirt_conf_dir:
|
|||||||
- group: 939
|
- group: 939
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
|
libvirt_volumes:
|
||||||
|
file.directory:
|
||||||
|
- name: /nsm/libvirt/volumes
|
||||||
|
- user: qemu
|
||||||
|
- group: qemu
|
||||||
|
- dir_mode: 755
|
||||||
|
- file_mode: 640
|
||||||
|
- recurse:
|
||||||
|
- user
|
||||||
|
- group
|
||||||
|
- mode
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
libvirt_config:
|
libvirt_config:
|
||||||
file.managed:
|
file.managed:
|
||||||
- name: /opt/so/conf/libvirt/libvirtd.conf
|
- name: /opt/so/conf/libvirt/libvirtd.conf
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
logrotate:
|
logrotate:
|
||||||
config:
|
config:
|
||||||
/opt/so/log/idstools/*_x_log:
|
|
||||||
- daily
|
|
||||||
- rotate 14
|
|
||||||
- missingok
|
|
||||||
- copytruncate
|
|
||||||
- compress
|
|
||||||
- create
|
|
||||||
- extension .log
|
|
||||||
- dateext
|
|
||||||
- dateyesterday
|
|
||||||
/opt/so/log/nginx/*_x_log:
|
/opt/so/log/nginx/*_x_log:
|
||||||
- daily
|
- daily
|
||||||
- rotate 14
|
- rotate 14
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
logrotate:
|
logrotate:
|
||||||
config:
|
config:
|
||||||
"/opt/so/log/idstools/*_x_log":
|
|
||||||
description: List of logrotate options for this file.
|
|
||||||
title: /opt/so/log/idstools/*.log
|
|
||||||
advanced: True
|
|
||||||
multiline: True
|
|
||||||
global: True
|
|
||||||
forcedType: "[]string"
|
|
||||||
"/opt/so/log/nginx/*_x_log":
|
"/opt/so/log/nginx/*_x_log":
|
||||||
description: List of logrotate options for this file.
|
description: List of logrotate options for this file.
|
||||||
title: /opt/so/log/nginx/*.log
|
title: /opt/so/log/nginx/*.log
|
||||||
|
|||||||
@@ -206,10 +206,33 @@ git_config_set_safe_dirs:
|
|||||||
- multivar:
|
- multivar:
|
||||||
- /nsm/rules/custom-local-repos/local-sigma
|
- /nsm/rules/custom-local-repos/local-sigma
|
||||||
- /nsm/rules/custom-local-repos/local-yara
|
- /nsm/rules/custom-local-repos/local-yara
|
||||||
|
- /nsm/rules/custom-local-repos/local-suricata
|
||||||
- /nsm/securityonion-resources
|
- /nsm/securityonion-resources
|
||||||
- /opt/so/conf/soc/ai_summary_repos/securityonion-resources
|
- /opt/so/conf/soc/ai_summary_repos/securityonion-resources
|
||||||
- /nsm/airgap-resources/playbooks
|
- /nsm/airgap-resources/playbooks
|
||||||
- /opt/so/conf/soc/playbooks
|
- /opt/so/conf/soc/playbooks
|
||||||
|
|
||||||
|
surinsmrulesdir:
|
||||||
|
file.directory:
|
||||||
|
- name: /nsm/rules/suricata
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
suriextractionrules:
|
||||||
|
file.managed:
|
||||||
|
- name: /nsm/rules/suricata/so_extraction.rules
|
||||||
|
- source: salt://suricata/files/so_extraction.rules
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
|
||||||
|
surifiltersrules:
|
||||||
|
file.managed:
|
||||||
|
- name: /nsm/rules/suricata/so_filters.rules
|
||||||
|
- source: salt://suricata/files/so_filters.rules
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
@@ -25,13 +25,11 @@
|
|||||||
{% set index_settings = es.get('index_settings', {}) %}
|
{% set index_settings = es.get('index_settings', {}) %}
|
||||||
{% set input = index_settings.get('so-logs', {}) %}
|
{% set input = index_settings.get('so-logs', {}) %}
|
||||||
{% for k in matched_integration_names %}
|
{% for k in matched_integration_names %}
|
||||||
{% if k not in index_settings %}
|
{% do index_settings.update({k: input}) %}
|
||||||
{% set _ = index_settings.update({k: input}) %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for k in addon_integration_keys %}
|
{% for k in addon_integration_keys %}
|
||||||
{% if k not in matched_integration_names and k in index_settings %}
|
{% if k not in matched_integration_names and k in index_settings %}
|
||||||
{% set _ = index_settings.pop(k) %}
|
{% do index_settings.pop(k) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ data }}
|
{{ data }}
|
||||||
@@ -45,14 +43,12 @@
|
|||||||
{% set es = data.get('elasticsearch', {}) %}
|
{% set es = data.get('elasticsearch', {}) %}
|
||||||
{% set index_settings = es.get('index_settings', {}) %}
|
{% set index_settings = es.get('index_settings', {}) %}
|
||||||
{% for k in matched_integration_names %}
|
{% for k in matched_integration_names %}
|
||||||
{% if k not in index_settings %}
|
{% set input = ADDON_INTEGRATION_DEFAULTS[k] %}
|
||||||
{% set input = ADDON_INTEGRATION_DEFAULTS[k] %}
|
{% do index_settings.update({k: input})%}
|
||||||
{% set _ = index_settings.update({k: input})%}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for k in addon_integration_keys %}
|
{% for k in addon_integration_keys %}
|
||||||
{% if k not in matched_integration_names and k in index_settings %}
|
{% if k not in matched_integration_names and k in index_settings %}
|
||||||
{% set _ = index_settings.pop(k) %}
|
{% do index_settings.pop(k) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ data }}
|
{{ data }}
|
||||||
|
|||||||
@@ -604,16 +604,6 @@ function add_kratos_to_minion() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_idstools_to_minion() {
|
|
||||||
printf '%s\n'\
|
|
||||||
"idstools:"\
|
|
||||||
" enabled: True"\
|
|
||||||
" " >> $PILLARFILE
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
log "ERROR" "Failed to add idstools configuration to $PILLARFILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function add_elastic_fleet_package_registry_to_minion() {
|
function add_elastic_fleet_package_registry_to_minion() {
|
||||||
printf '%s\n'\
|
printf '%s\n'\
|
||||||
@@ -741,7 +731,6 @@ function createEVAL() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +751,6 @@ function createSTANDALONE() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +767,6 @@ function createMANAGER() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,7 +783,6 @@ function createMANAGERSEARCH() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,7 +797,6 @@ function createIMPORT() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -896,7 +881,6 @@ function createMANAGERHYPE() {
|
|||||||
add_soc_to_minion || return 1
|
add_soc_to_minion || return 1
|
||||||
add_registry_to_minion || return 1
|
add_registry_to_minion || return 1
|
||||||
add_kratos_to_minion || return 1
|
add_kratos_to_minion || return 1
|
||||||
add_idstools_to_minion || return 1
|
|
||||||
add_elastic_fleet_package_registry_to_minion || return 1
|
add_elastic_fleet_package_registry_to_minion || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ def showUsage(args):
|
|||||||
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]), file=sys.stderr)
|
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]), file=sys.stderr)
|
||||||
print(' General commands:', file=sys.stderr)
|
print(' General commands:', file=sys.stderr)
|
||||||
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||||
|
print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||||
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
||||||
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
||||||
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
||||||
@@ -26,8 +27,8 @@ def showUsage(args):
|
|||||||
print(' Where:', file=sys.stderr)
|
print(' Where:', file=sys.stderr)
|
||||||
print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr)
|
print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr)
|
||||||
print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr)
|
print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr)
|
||||||
print(' VALUE - Value to set for a given key', file=sys.stderr)
|
print(' VALUE - Value to set for a given key. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||||
print(' LISTITEM - Item to append to a given key\'s list value', file=sys.stderr)
|
print(' LISTITEM - Item to append to a given key\'s list value. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -57,8 +58,32 @@ def appendItem(content, key, listItem):
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def removeListItem(content, key, listItem):
|
||||||
|
pieces = key.split(".", 1)
|
||||||
|
if len(pieces) > 1:
|
||||||
|
removeListItem(content[pieces[0]], pieces[1], listItem)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if not isinstance(content[key], list):
|
||||||
|
raise AttributeError("Value is not a list")
|
||||||
|
if listItem in content[key]:
|
||||||
|
content[key].remove(listItem)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
except KeyError:
|
||||||
|
print("The key provided does not exist. No action was taken on the file.", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def convertType(value):
|
def convertType(value):
|
||||||
if isinstance(value, str) and len(value) > 0 and (not value.startswith("0") or len(value) == 1):
|
if isinstance(value, str) and value.startswith("file:"):
|
||||||
|
path = value[5:] # Remove "file:" prefix
|
||||||
|
if not os.path.exists(path):
|
||||||
|
print(f"File '{path}' does not exist.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
return loadYaml(path)
|
||||||
|
elif isinstance(value, str) and len(value) > 0 and (not value.startswith("0") or len(value) == 1):
|
||||||
if "." in value:
|
if "." in value:
|
||||||
try:
|
try:
|
||||||
value = float(value)
|
value = float(value)
|
||||||
@@ -97,6 +122,23 @@ def append(args):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def removelistitem(args):
|
||||||
|
if len(args) != 3:
|
||||||
|
print('Missing filename, key arg, or list item to remove', file=sys.stderr)
|
||||||
|
showUsage(None)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
filename = args[0]
|
||||||
|
key = args[1]
|
||||||
|
listItem = args[2]
|
||||||
|
|
||||||
|
content = loadYaml(filename)
|
||||||
|
removeListItem(content, key, convertType(listItem))
|
||||||
|
writeYaml(filename, content)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def addKey(content, key, value):
|
def addKey(content, key, value):
|
||||||
pieces = key.split(".", 1)
|
pieces = key.split(".", 1)
|
||||||
if len(pieces) > 1:
|
if len(pieces) > 1:
|
||||||
@@ -205,6 +247,7 @@ def main():
|
|||||||
"help": showUsage,
|
"help": showUsage,
|
||||||
"add": add,
|
"add": add,
|
||||||
"append": append,
|
"append": append,
|
||||||
|
"removelistitem": removelistitem,
|
||||||
"get": get,
|
"get": get,
|
||||||
"remove": remove,
|
"remove": remove,
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
|||||||
@@ -361,6 +361,29 @@ class TestRemove(unittest.TestCase):
|
|||||||
self.assertEqual(soyaml.convertType("FALSE"), False)
|
self.assertEqual(soyaml.convertType("FALSE"), False)
|
||||||
self.assertEqual(soyaml.convertType(""), "")
|
self.assertEqual(soyaml.convertType(""), "")
|
||||||
|
|
||||||
|
def test_convert_file(self):
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Create a temporary YAML file
|
||||||
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||||
|
f.write("test:\n - name: hi\n color: blue\n")
|
||||||
|
temp_file = f.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = soyaml.convertType(f"file:{temp_file}")
|
||||||
|
expected = {"test": [{"name": "hi", "color": "blue"}]}
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
finally:
|
||||||
|
os.unlink(temp_file)
|
||||||
|
|
||||||
|
def test_convert_file_nonexistent(self):
|
||||||
|
with self.assertRaises(SystemExit) as cm:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
soyaml.convertType("file:/nonexistent/file.yaml")
|
||||||
|
self.assertEqual(cm.exception.code, 1)
|
||||||
|
self.assertIn("File '/nonexistent/file.yaml' does not exist.", mock_stderr.getvalue())
|
||||||
|
|
||||||
def test_get_int(self):
|
def test_get_int(self):
|
||||||
with patch('sys.stdout', new=StringIO()) as mock_stdout:
|
with patch('sys.stdout', new=StringIO()) as mock_stdout:
|
||||||
filename = "/tmp/so-yaml_test-get.yaml"
|
filename = "/tmp/so-yaml_test-get.yaml"
|
||||||
@@ -434,3 +457,126 @@ class TestRemove(unittest.TestCase):
|
|||||||
self.assertEqual(result, 1)
|
self.assertEqual(result, 1)
|
||||||
self.assertIn("Missing filename or key arg", mock_stderr.getvalue())
|
self.assertIn("Missing filename or key arg", mock_stderr.getvalue())
|
||||||
sysmock.assert_called_once_with(1)
|
sysmock.assert_called_once_with(1)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveListItem(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_removelistitem_missing_arg(self):
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "help"]
|
||||||
|
soyaml.removelistitem(["file", "key"])
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertIn("Missing filename, key arg, or list item to remove", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: abc }, key2: false, key3: [a,b,c]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key3", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2: abc\nkey2: false\nkey3:\n- a\n- c\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_nested(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: [a,b,c] }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1.child2", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2:\n - a\n - c\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_nested_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1.child2.deep2", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - a\n - c\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_item_not_in_list(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: [a,b,c]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1", "d"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n- a\n- b\n- c\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_key_noexist(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key4", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_noexist_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1.child2.deep3", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_nonlist(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_nonlist_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1.child2.deep1", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ whiptail_title='Security Onion UPdater'
|
|||||||
NOTIFYCUSTOMELASTICCONFIG=false
|
NOTIFYCUSTOMELASTICCONFIG=false
|
||||||
TOPFILE=/opt/so/saltstack/default/salt/top.sls
|
TOPFILE=/opt/so/saltstack/default/salt/top.sls
|
||||||
BACKUPTOPFILE=/opt/so/saltstack/default/salt/top.sls.backup
|
BACKUPTOPFILE=/opt/so/saltstack/default/salt/top.sls.backup
|
||||||
|
SALTUPGRADED=false
|
||||||
|
SALT_CLOUD_INSTALLED=false
|
||||||
|
SALT_CLOUD_CONFIGURED=false
|
||||||
# used to display messages to the user at the end of soup
|
# used to display messages to the user at the end of soup
|
||||||
declare -a FINAL_MESSAGE_QUEUE=()
|
declare -a FINAL_MESSAGE_QUEUE=()
|
||||||
|
|
||||||
@@ -271,7 +274,7 @@ check_os_updates() {
|
|||||||
if [[ "$confirm" == [cC] ]]; then
|
if [[ "$confirm" == [cC] ]]; then
|
||||||
echo "Continuing without updating packages"
|
echo "Continuing without updating packages"
|
||||||
elif [[ "$confirm" == [uU] ]]; then
|
elif [[ "$confirm" == [uU] ]]; then
|
||||||
echo "Applying Grid Updates"
|
echo "Applying Grid Updates. The following patch.os salt state may take a while depending on how many packages need to be updated."
|
||||||
update_flag=true
|
update_flag=true
|
||||||
else
|
else
|
||||||
echo "Exiting soup"
|
echo "Exiting soup"
|
||||||
@@ -423,6 +426,7 @@ preupgrade_changes() {
|
|||||||
[[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170
|
[[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170
|
||||||
[[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180
|
[[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180
|
||||||
[[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190
|
[[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190
|
||||||
|
[[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,6 +458,7 @@ postupgrade_changes() {
|
|||||||
[[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170
|
[[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170
|
||||||
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
||||||
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
||||||
|
[[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,6 +638,13 @@ post_to_2.4.190() {
|
|||||||
POSTVERSION=2.4.190
|
POSTVERSION=2.4.190
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post_to_2.4.200() {
|
||||||
|
echo "Initiating Suricata idstools migration..."
|
||||||
|
suricata_idstools_removal_post
|
||||||
|
|
||||||
|
POSTVERSION=2.4.200
|
||||||
|
}
|
||||||
|
|
||||||
repo_sync() {
|
repo_sync() {
|
||||||
echo "Sync the local repo."
|
echo "Sync the local repo."
|
||||||
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
||||||
@@ -900,6 +912,15 @@ up_to_2.4.190() {
|
|||||||
INSTALLEDVERSION=2.4.190
|
INSTALLEDVERSION=2.4.190
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up_to_2.4.200() {
|
||||||
|
echo "Backing up idstools config..."
|
||||||
|
suricata_idstools_removal_pre
|
||||||
|
|
||||||
|
touch /opt/so/state/esfleet_logstash_config_pillar
|
||||||
|
|
||||||
|
INSTALLEDVERSION=2.4.200
|
||||||
|
}
|
||||||
|
|
||||||
add_hydra_pillars() {
|
add_hydra_pillars() {
|
||||||
mkdir -p /opt/so/saltstack/local/pillar/hydra
|
mkdir -p /opt/so/saltstack/local/pillar/hydra
|
||||||
touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls
|
touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls
|
||||||
@@ -983,6 +1004,8 @@ rollover_index() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suricata_idstools_migration() {
|
suricata_idstools_migration() {
|
||||||
|
# For 2.4.70
|
||||||
|
|
||||||
#Backup the pillars for idstools
|
#Backup the pillars for idstools
|
||||||
mkdir -p /nsm/backup/detections-migration/idstools
|
mkdir -p /nsm/backup/detections-migration/idstools
|
||||||
rsync -av /opt/so/saltstack/local/pillar/idstools/* /nsm/backup/detections-migration/idstools
|
rsync -av /opt/so/saltstack/local/pillar/idstools/* /nsm/backup/detections-migration/idstools
|
||||||
@@ -1083,6 +1106,209 @@ playbook_migration() {
|
|||||||
echo "Playbook Migration is complete...."
|
echo "Playbook Migration is complete...."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suricata_idstools_removal_pre() {
|
||||||
|
# For SOUPs beginning with 2.4.200 - pre SOUP checks
|
||||||
|
|
||||||
|
# Create syncBlock file
|
||||||
|
install -d -o 939 -g 939 -m 755 /opt/so/conf/soc/fingerprints
|
||||||
|
install -o 939 -g 939 -m 644 /dev/null /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF
|
||||||
|
Suricata ruleset sync is blocked until this file is removed. Make sure that you have manually added any custom Suricata rulesets via SOC config - review the documentation for more details: securityonion.net/docs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Backup custom rules & overrides
|
||||||
|
mkdir -p /nsm/backup/detections-migration/2-4-200
|
||||||
|
cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200
|
||||||
|
cp /opt/so/conf/idstools/etc/rulecat.conf /nsm/backup/detections-migration/2-4-200
|
||||||
|
|
||||||
|
if [[ -f /opt/so/conf/soc/so-detections-backup.py ]]; then
|
||||||
|
python3 /opt/so/conf/soc/so-detections-backup.py
|
||||||
|
|
||||||
|
# Verify backup by comparing counts
|
||||||
|
echo "Verifying detection overrides backup..."
|
||||||
|
es_override_count=$(/sbin/so-elasticsearch-query 'so-detection/_count' \
|
||||||
|
-d '{"query": {"bool": {"must": [{"exists": {"field": "so_detection.overrides"}}]}}}' | jq -r '.count') || {
|
||||||
|
echo " Error: Failed to query Elasticsearch for override count"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ! "$es_override_count" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo " Error: Invalid override count from Elasticsearch: '$es_override_count'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
backup_override_count=$(find /nsm/backup/detections/repo/*/overrides -type f 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
echo " Elasticsearch overrides: $es_override_count"
|
||||||
|
echo " Backed up overrides: $backup_override_count"
|
||||||
|
|
||||||
|
if [[ "$es_override_count" -gt 0 ]]; then
|
||||||
|
if [[ "$backup_override_count" -gt 0 ]]; then
|
||||||
|
echo " Override backup verified successfully"
|
||||||
|
else
|
||||||
|
echo " Error: Elasticsearch has $es_override_count overrides but backup has 0 files"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " No overrides to backup"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "SOC Detections backup script not found, skipping detection backup"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suricata_idstools_removal_post() {
|
||||||
|
# For SOUPs beginning with 2.4.200 - post SOUP checks
|
||||||
|
|
||||||
|
echo "Checking idstools configuration for custom modifications..."
|
||||||
|
|
||||||
|
# Normalize and hash file content for consistent comparison
|
||||||
|
# Args: $1 - file path
|
||||||
|
# Outputs: SHA256 hash to stdout
|
||||||
|
# Returns: 0 on success, 1 on failure
|
||||||
|
hash_normalized_file() {
|
||||||
|
local file="$1"
|
||||||
|
|
||||||
|
if [[ ! -r "$file" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -E \
|
||||||
|
-e 's/^[[:space:]]+//; s/[[:space:]]+$//' \
|
||||||
|
-e '/^$/d' \
|
||||||
|
-e 's|--url=http://[^:]+:7788|--url=http://MANAGER:7788|' \
|
||||||
|
"$file" | sha256sum | awk '{print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Known-default hashes for so-rule-update (ETOPEN ruleset)
|
||||||
|
KNOWN_SO_RULE_UPDATE_HASHES=(
|
||||||
|
# 2.4.100+ (suricata 7.0.3, non-airgap)
|
||||||
|
"5fbd067ced86c8ec72ffb7e1798aa624123b536fb9d78f4b3ad8d3b45db1eae7" # 2.4.100-2.4.190 non-Airgap
|
||||||
|
# 2.4.90+ airgap (same for 2.4.90 and 2.4.100+)
|
||||||
|
"61f632c55791338c438c071040f1490066769bcce808b595b5cc7974a90e653a" # 2.4.90+ Airgap
|
||||||
|
# 2.4.90 (suricata 6.0, non-airgap, comment inside proxy block)
|
||||||
|
"0380ec52a05933244ab0f0bc506576e1d838483647b40612d5fe4b378e47aedd" # 2.4.90 non-Airgap
|
||||||
|
# 2.4.10-2.4.80 (suricata 6.0, non-airgap, comment outside proxy block)
|
||||||
|
"b6e4d1b5a78d57880ad038a9cd2cc6978aeb2dd27d48ea1a44dd866a2aee7ff4" # 2.4.10-2.4.80 non-Airgap
|
||||||
|
# 2.4.10-2.4.80 airgap
|
||||||
|
"b20146526ace2b142fde4664f1386a9a1defa319b3a1d113600ad33a1b037dad" # 2.4.10-2.4.80 Airgap
|
||||||
|
# 2.4.5 and earlier (no pidof check, non-airgap)
|
||||||
|
"d04f5e4015c348133d28a7840839e82d60009781eaaa1c66f7f67747703590dc" # 2.4.5 non-Airgap
|
||||||
|
)
|
||||||
|
|
||||||
|
# Known-default hashes for rulecat.conf
|
||||||
|
KNOWN_RULECAT_CONF_HASHES=(
|
||||||
|
# 2.4.100+ (suricata 7.0.3)
|
||||||
|
"302e75dca9110807f09ade2eec3be1fcfc8b2bf6cf2252b0269bb72efeefe67e" # 2.4.100-2.4.190 without SURICATA md_engine
|
||||||
|
"8029b7718c324a9afa06a5cf180afde703da1277af4bdd30310a6cfa3d6398cb" # 2.4.100-2.4.190 with SURICATA md_engine
|
||||||
|
# 2.4.80-2.4.90 (suricata 6.0, with --suricata-version and --output)
|
||||||
|
"4d8b318e6950a6f60b02f307cf27c929efd39652990c1bd0c8820aa8a307e1e7" # 2.4.80-2.4.90 without SURICATA md_engine
|
||||||
|
"a1ddf264c86c4e91c81c5a317f745a19466d4311e4533ec3a3c91fed04c11678" # 2.4.80-2.4.90 with SURICATA md_engine
|
||||||
|
# 2.4.50-2.4.70 (/suri/ path, no --suricata-version)
|
||||||
|
"86e3afb8d0f00c62337195602636864c98580a13ca9cc85029661a539deae6ae" # 2.4.50-2.4.70 without SURICATA md_engine
|
||||||
|
"5a97604ca5b820a10273a2d6546bb5e00c5122ca5a7dfe0ba0bfbce5fc026f4b" # 2.4.50-2.4.70 with SURICATA md_engine
|
||||||
|
# 2.4.20-2.4.40 (/nids/ path without /suri/)
|
||||||
|
"d098ea9ecd94b5cca35bf33543f8ea8f48066a0785221fabda7fef43d2462c29" # 2.4.20-2.4.40 without SURICATA md_engine
|
||||||
|
"9dbc60df22ae20d65738ba42e620392577857038ba92278e23ec182081d191cd" # 2.4.20-2.4.40 with SURICATA md_engine
|
||||||
|
# 2.4.5-2.4.10 (/sorules/ path for extraction/filters)
|
||||||
|
"490f6843d9fca759ee74db3ada9c702e2440b8393f2cfaf07bbe41aaa6d955c3" # 2.4.5-2.4.10 with SURICATA md_engine
|
||||||
|
# Note: 2.4.5-2.4.10 without SURICATA md_engine has same hash as 2.4.20-2.4.40 without SURICATA md_engine
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check a config file against known hashes
|
||||||
|
# Args: $1 - file path, $2 - array name of known hashes
|
||||||
|
check_config_file() {
|
||||||
|
local file="$1"
|
||||||
|
local known_hashes_array="$2"
|
||||||
|
local file_display_name=$(basename "$file")
|
||||||
|
|
||||||
|
if [[ ! -f "$file" ]]; then
|
||||||
|
echo "Warning: $file not found"
|
||||||
|
echo "$file_display_name not found - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Hashing $file..."
|
||||||
|
local file_hash
|
||||||
|
if ! file_hash=$(hash_normalized_file "$file"); then
|
||||||
|
echo "Warning: Could not read $file"
|
||||||
|
echo "$file_display_name not readable - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Hash: $file_hash"
|
||||||
|
|
||||||
|
# Check if hash matches any known default
|
||||||
|
local -n known_hashes=$known_hashes_array
|
||||||
|
for known_hash in "${known_hashes[@]}"; do
|
||||||
|
if [[ "$file_hash" == "$known_hash" ]]; then
|
||||||
|
echo " Matches known default configuration"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# No match - custom configuration detected
|
||||||
|
echo "Does not match known default - custom configuration detected"
|
||||||
|
echo "Custom $file_display_name detected (hash: $file_hash)" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
|
||||||
|
# If this is so-rule-update, check for ETPRO license code and write out to the syncBlock file
|
||||||
|
# If ETPRO is enabled, the license code already exists in the so-rule-update script, this is just making it easier to migrate
|
||||||
|
if [[ "$file_display_name" == "so-rule-update" ]]; then
|
||||||
|
local etpro_code
|
||||||
|
etpro_code=$(grep -oP '\-\-etpro=\K[0-9a-fA-F]+' "$file" 2>/dev/null) || true
|
||||||
|
if [[ -n "$etpro_code" ]]; then
|
||||||
|
echo "ETPRO code found: $etpro_code" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check so-rule-update and rulecat.conf
|
||||||
|
SO_RULE_UPDATE="/usr/sbin/so-rule-update"
|
||||||
|
RULECAT_CONF="/opt/so/conf/idstools/etc/rulecat.conf"
|
||||||
|
|
||||||
|
custom_found=0
|
||||||
|
|
||||||
|
check_config_file "$SO_RULE_UPDATE" "KNOWN_SO_RULE_UPDATE_HASHES" || custom_found=1
|
||||||
|
check_config_file "$RULECAT_CONF" "KNOWN_RULECAT_CONF_HASHES" || custom_found=1
|
||||||
|
|
||||||
|
# If no custom configs found, remove syncBlock
|
||||||
|
if [[ $custom_found -eq 0 ]]; then
|
||||||
|
echo "idstools migration completed successfully - removing Suricata engine syncBlock"
|
||||||
|
rm -f /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
|
else
|
||||||
|
echo "Custom idstools configuration detected - syncBlock remains in place"
|
||||||
|
echo "Review /opt/so/conf/soc/fingerprints/suricataengine.syncBlock for details"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Cleaning up idstools"
|
||||||
|
echo "Stopping and removing the idstools container..."
|
||||||
|
if [ -n "$(docker ps -q -f name=^so-idstools$)" ]; then
|
||||||
|
image_name=$(docker ps -a --filter name=^so-idstools$ --format '{{.Image}}' 2>/dev/null || true)
|
||||||
|
docker stop so-idstools || echo "Warning: failed to stop so-idstools container"
|
||||||
|
docker rm so-idstools || echo "Warning: failed to remove so-idstools container"
|
||||||
|
|
||||||
|
if [[ -n "$image_name" ]]; then
|
||||||
|
echo "Removing idstools image: $image_name"
|
||||||
|
docker rmi "$image_name" || echo "Warning: failed to remove image $image_name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Removing idstools symlink and scripts..."
|
||||||
|
rm /opt/so/saltstack/local/salt/suricata/rules
|
||||||
|
rm -rf /usr/sbin/so-idstools*
|
||||||
|
sed -i '/^#\?so-idstools$/d' /opt/so/conf/so-status/so-status.conf
|
||||||
|
|
||||||
|
# Backup the salt master config & manager pillar before editing it
|
||||||
|
cp /opt/so/saltstack/local/pillar/minions/$MINIONID.sls /nsm/backup/detections-migration/2-4-200/
|
||||||
|
cp /etc/salt/master /nsm/backup/detections-migration/2-4-200/
|
||||||
|
so-yaml.py remove /opt/so/saltstack/local/pillar/minions/$MINIONID.sls idstools
|
||||||
|
so-yaml.py removelistitem /etc/salt/master file_roots.base /opt/so/rules/nids
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
determine_elastic_agent_upgrade() {
|
determine_elastic_agent_upgrade() {
|
||||||
if [[ $is_airgap -eq 0 ]]; then
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
update_elastic_agent_airgap
|
update_elastic_agent_airgap
|
||||||
@@ -1260,24 +1486,43 @@ upgrade_check_salt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
upgrade_salt() {
|
upgrade_salt() {
|
||||||
SALTUPGRADED=True
|
|
||||||
echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION."
|
echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION."
|
||||||
echo ""
|
echo ""
|
||||||
# If rhel family
|
# If rhel family
|
||||||
if [[ $is_rpm ]]; then
|
if [[ $is_rpm ]]; then
|
||||||
|
# Check if salt-cloud is installed
|
||||||
|
if rpm -q salt-cloud &>/dev/null; then
|
||||||
|
SALT_CLOUD_INSTALLED=true
|
||||||
|
fi
|
||||||
|
# Check if salt-cloud is configured
|
||||||
|
if [[ -f /etc/salt/cloud.profiles.d/socloud.conf ]]; then
|
||||||
|
SALT_CLOUD_CONFIGURED=true
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Removing yum versionlock for Salt."
|
echo "Removing yum versionlock for Salt."
|
||||||
echo ""
|
echo ""
|
||||||
yum versionlock delete "salt"
|
yum versionlock delete "salt"
|
||||||
yum versionlock delete "salt-minion"
|
yum versionlock delete "salt-minion"
|
||||||
yum versionlock delete "salt-master"
|
yum versionlock delete "salt-master"
|
||||||
|
# Remove salt-cloud versionlock if installed
|
||||||
|
if [[ $SALT_CLOUD_INSTALLED == true ]]; then
|
||||||
|
yum versionlock delete "salt-cloud"
|
||||||
|
fi
|
||||||
echo "Updating Salt packages."
|
echo "Updating Salt packages."
|
||||||
echo ""
|
echo ""
|
||||||
set +e
|
set +e
|
||||||
# if oracle run with -r to ignore repos set by bootstrap
|
# if oracle run with -r to ignore repos set by bootstrap
|
||||||
if [[ $OS == 'oracle' ]]; then
|
if [[ $OS == 'oracle' ]]; then
|
||||||
run_check_net_err \
|
# Add -L flag only if salt-cloud is already installed
|
||||||
"sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M stable \"$NEWSALTVERSION\"" \
|
if [[ $SALT_CLOUD_INSTALLED == true ]]; then
|
||||||
"Could not update salt, please check $SOUP_LOG for details."
|
run_check_net_err \
|
||||||
|
"sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -L -F -M stable \"$NEWSALTVERSION\"" \
|
||||||
|
"Could not update salt, please check $SOUP_LOG for details."
|
||||||
|
else
|
||||||
|
run_check_net_err \
|
||||||
|
"sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M stable \"$NEWSALTVERSION\"" \
|
||||||
|
"Could not update salt, please check $SOUP_LOG for details."
|
||||||
|
fi
|
||||||
# if another rhel family variant we want to run without -r to allow the bootstrap script to manage repos
|
# if another rhel family variant we want to run without -r to allow the bootstrap script to manage repos
|
||||||
else
|
else
|
||||||
run_check_net_err \
|
run_check_net_err \
|
||||||
@@ -1290,8 +1535,14 @@ upgrade_salt() {
|
|||||||
yum versionlock add "salt-0:$NEWSALTVERSION-0.*"
|
yum versionlock add "salt-0:$NEWSALTVERSION-0.*"
|
||||||
yum versionlock add "salt-minion-0:$NEWSALTVERSION-0.*"
|
yum versionlock add "salt-minion-0:$NEWSALTVERSION-0.*"
|
||||||
yum versionlock add "salt-master-0:$NEWSALTVERSION-0.*"
|
yum versionlock add "salt-master-0:$NEWSALTVERSION-0.*"
|
||||||
|
# Add salt-cloud versionlock if installed
|
||||||
|
if [[ $SALT_CLOUD_INSTALLED == true ]]; then
|
||||||
|
yum versionlock add "salt-cloud-0:$NEWSALTVERSION-0.*"
|
||||||
|
fi
|
||||||
# Else do Ubuntu things
|
# Else do Ubuntu things
|
||||||
elif [[ $is_deb ]]; then
|
elif [[ $is_deb ]]; then
|
||||||
|
# ensure these files don't exist when upgrading from 3006.9 to 3006.16
|
||||||
|
rm -f /etc/apt/keyrings/salt-archive-keyring-2023.pgp /etc/apt/sources.list.d/salt.list
|
||||||
echo "Removing apt hold for Salt."
|
echo "Removing apt hold for Salt."
|
||||||
echo ""
|
echo ""
|
||||||
apt-mark unhold "salt-common"
|
apt-mark unhold "salt-common"
|
||||||
@@ -1322,6 +1573,7 @@ upgrade_salt() {
|
|||||||
echo ""
|
echo ""
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
|
SALTUPGRADED=true
|
||||||
echo "Salt upgrade success."
|
echo "Salt upgrade success."
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
@@ -1565,6 +1817,11 @@ main() {
|
|||||||
# ensure the mine is updated and populated before highstates run, following the salt-master restart
|
# ensure the mine is updated and populated before highstates run, following the salt-master restart
|
||||||
update_salt_mine
|
update_salt_mine
|
||||||
|
|
||||||
|
if [[ $SALT_CLOUD_CONFIGURED == true && $SALTUPGRADED == true ]]; then
|
||||||
|
echo "Updating salt-cloud config to use the new Salt version"
|
||||||
|
salt-call state.apply salt.cloud.config concurrent=True
|
||||||
|
fi
|
||||||
|
|
||||||
enable_highstate
|
enable_highstate
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
@@ -1647,7 +1904,7 @@ This appears to be a distributed deployment. Other nodes should update themselve
|
|||||||
|
|
||||||
Each minion is on a random 15 minute check-in period and things like network bandwidth can be a factor in how long the actual upgrade takes. If you have a heavy node on a slow link, it is going to take a while to get the containers to it. Depending on what changes happened between the versions, Elasticsearch might not be able to talk to said heavy node until the update is complete.
|
Each minion is on a random 15 minute check-in period and things like network bandwidth can be a factor in how long the actual upgrade takes. If you have a heavy node on a slow link, it is going to take a while to get the containers to it. Depending on what changes happened between the versions, Elasticsearch might not be able to talk to said heavy node until the update is complete.
|
||||||
|
|
||||||
If it looks like you’re missing data after the upgrade, please avoid restarting services and instead make sure at least one search node has completed its upgrade. The best way to do this is to run 'sudo salt-call state.highstate' from a search node and make sure there are no errors. Typically if it works on one node it will work on the rest. Forward nodes are less complex and will update as they check in so you can monitor those from the Grid section of SOC.
|
If it looks like you’re missing data after the upgrade, please avoid restarting services and instead make sure at least one search node has completed its upgrade. The best way to do this is to run 'sudo salt-call state.highstate' from a search node and make sure there are no errors. Typically if it works on one node it will work on the rest. Sensor nodes are less complex and will update as they check in so you can monitor those from the Grid section of SOC.
|
||||||
|
|
||||||
For more information, please see $DOC_BASE_URL/soup.html#distributed-deployments.
|
For more information, please see $DOC_BASE_URL/soup.html#distributed-deployments.
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,9 @@
|
|||||||
|
|
||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from "pcap/config.map.jinja" import PCAPMERGED %}
|
{% from "pcap/config.map.jinja" import PCAPMERGED %}
|
||||||
{% from 'bpf/pcap.map.jinja' import PCAPBPF %}
|
{% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS, PCAP_BPF_CALC, STENO_BPF_COMPILED %}
|
||||||
|
|
||||||
{% set BPF_COMPILED = "" %}
|
|
||||||
|
|
||||||
# PCAP Section
|
# PCAP Section
|
||||||
|
|
||||||
stenographergroup:
|
stenographergroup:
|
||||||
group.present:
|
group.present:
|
||||||
- name: stenographer
|
- name: stenographer
|
||||||
@@ -40,18 +37,12 @@ pcap_sbin:
|
|||||||
- group: 939
|
- group: 939
|
||||||
- file_mode: 755
|
- file_mode: 755
|
||||||
|
|
||||||
{% if PCAPBPF %}
|
{% if PCAPBPF and not PCAP_BPF_STATUS %}
|
||||||
{% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %}
|
stenoPCAPbpfcompilationfailure:
|
||||||
{% if BPF_CALC['stderr'] == "" %}
|
|
||||||
{% set BPF_COMPILED = ",\\\"--filter=" + BPF_CALC['stdout'] + "\\\"" %}
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
bpfcompilationfailure:
|
|
||||||
test.configurable_test_state:
|
test.configurable_test_state:
|
||||||
- changes: False
|
- changes: False
|
||||||
- result: False
|
- result: False
|
||||||
- comment: "BPF Compilation Failed - Discarding Specified BPF"
|
- comment: "BPF Syntax Error - Discarding Specified BPF. Error: {{ PCAP_BPF_CALC['stderr'] }}"
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
stenoconf:
|
stenoconf:
|
||||||
@@ -64,7 +55,7 @@ stenoconf:
|
|||||||
- template: jinja
|
- template: jinja
|
||||||
- defaults:
|
- defaults:
|
||||||
PCAPMERGED: {{ PCAPMERGED }}
|
PCAPMERGED: {{ PCAPMERGED }}
|
||||||
BPF_COMPILED: "{{ BPF_COMPILED }}"
|
STENO_BPF_COMPILED: "{{ STENO_BPF_COMPILED }}"
|
||||||
|
|
||||||
stenoca:
|
stenoca:
|
||||||
file.directory:
|
file.directory:
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
, "Interface": "{{ pillar.sensor.interface }}"
|
, "Interface": "{{ pillar.sensor.interface }}"
|
||||||
, "Port": 1234
|
, "Port": 1234
|
||||||
, "Host": "127.0.0.1"
|
, "Host": "127.0.0.1"
|
||||||
, "Flags": ["-v", "--blocks={{ PCAPMERGED.config.blocks }}", "--preallocate_file_mb={{ PCAPMERGED.config.preallocate_file_mb }}", "--aiops={{ PCAPMERGED.config.aiops }}", "--uid=stenographer", "--gid=stenographer"{{ BPF_COMPILED }}]
|
, "Flags": ["-v", "--blocks={{ PCAPMERGED.config.blocks }}", "--preallocate_file_mb={{ PCAPMERGED.config.preallocate_file_mb }}", "--aiops={{ PCAPMERGED.config.aiops }}", "--uid=stenographer", "--gid=stenographer"{{ STENO_BPF_COMPILED }}]
|
||||||
, "CertPath": "/etc/stenographer/certs"
|
, "CertPath": "/etc/stenographer/certs"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pcap:
|
|||||||
description: By default, Stenographer limits the number of files in the pcap directory to 30000 to avoid limitations with the ext3 filesystem. However, if you're using the ext4 or xfs filesystems, then it is safe to increase this value. So if you have a large amount of storage and find that you only have 3 weeks worth of PCAP on disk while still having plenty of free space, then you may want to increase this default setting.
|
description: By default, Stenographer limits the number of files in the pcap directory to 30000 to avoid limitations with the ext3 filesystem. However, if you're using the ext4 or xfs filesystems, then it is safe to increase this value. So if you have a large amount of storage and find that you only have 3 weeks worth of PCAP on disk while still having plenty of free space, then you may want to increase this default setting.
|
||||||
helpLink: stenographer.html
|
helpLink: stenographer.html
|
||||||
diskfreepercentage:
|
diskfreepercentage:
|
||||||
description: Stenographer will purge old PCAP on a regular basis to keep the disk free percentage at this level. If you have a distributed deployment with dedicated forward nodes, then the default value of 10 should be reasonable since Stenographer should be the main consumer of disk space in the /nsm partition. However, if you have systems that run both Stenographer and Elasticsearch at the same time (like eval and standalone installations), then you’ll want to make sure that this value is no lower than 21 so that you avoid Elasticsearch hitting its watermark setting at 80% disk usage. If you have an older standalone installation, then you may need to manually change this value to 21.
|
description: Stenographer will purge old PCAP on a regular basis to keep the disk free percentage at this level. If you have a distributed deployment with dedicated Sensor nodes, then the default value of 10 should be reasonable since Stenographer should be the main consumer of disk space in the /nsm partition. However, if you have systems that run both Stenographer and Elasticsearch at the same time (like eval and standalone installations), then you’ll want to make sure that this value is no lower than 21 so that you avoid Elasticsearch hitting its watermark setting at 80% disk usage. If you have an older standalone installation, then you may need to manually change this value to 21.
|
||||||
helpLink: stenographer.html
|
helpLink: stenographer.html
|
||||||
blocks:
|
blocks:
|
||||||
description: The number of 1MB packet blocks used by Stenographer and AF_PACKET to store packets in memory, per thread. You shouldn't need to change this.
|
description: The number of 1MB packet blocks used by Stenographer and AF_PACKET to store packets in memory, per thread. You shouldn't need to change this.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
{% if sls.split('.')[0] in allowed_states %}
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
{% from 'docker/docker.map.jinja' import DOCKER %}
|
||||||
|
|
||||||
include:
|
include:
|
||||||
@@ -57,6 +58,17 @@ so-dockerregistry:
|
|||||||
- x509: registry_crt
|
- x509: registry_crt
|
||||||
- x509: registry_key
|
- x509: registry_key
|
||||||
|
|
||||||
|
wait_for_so-dockerregistry:
|
||||||
|
http.wait_for_successful_query:
|
||||||
|
- name: 'https://{{ GLOBALS.registry_host }}:5000/v2/'
|
||||||
|
- ssl: True
|
||||||
|
- verify_ssl: False
|
||||||
|
- status: 200
|
||||||
|
- wait_for: 120
|
||||||
|
- request_interval: 5
|
||||||
|
- require:
|
||||||
|
- docker_container: so-dockerregistry
|
||||||
|
|
||||||
delete_so-dockerregistry_so-status.disabled:
|
delete_so-dockerregistry_so-status.disabled:
|
||||||
file.uncomment:
|
file.uncomment:
|
||||||
- name: /opt/so/conf/so-status/so-status.conf
|
- name: /opt/so/conf/so-status/so-status.conf
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ sool9_{{host}}:
|
|||||||
private_key: /etc/ssh/auth_keys/soqemussh/id_ecdsa
|
private_key: /etc/ssh/auth_keys/soqemussh/id_ecdsa
|
||||||
sudo: True
|
sudo: True
|
||||||
deploy_command: sh /tmp/.saltcloud-*/deploy.sh
|
deploy_command: sh /tmp/.saltcloud-*/deploy.sh
|
||||||
script_args: -r -F -x python3 stable 3006.9
|
script_args: -r -F -x python3 stable {{ SALTVERSION }}
|
||||||
minion:
|
minion:
|
||||||
master: {{ grains.host }}
|
master: {{ grains.host }}
|
||||||
master_port: 4506
|
master_port: 4506
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
{% if '.'.join(sls.split('.')[:2]) in allowed_states %}
|
{% if '.'.join(sls.split('.')[:2]) in allowed_states %}
|
||||||
{% if 'vrt' in salt['pillar.get']('features', []) %}
|
{% if 'vrt' in salt['pillar.get']('features', []) %}
|
||||||
{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %}
|
{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %}
|
||||||
|
{% from 'salt/map.jinja' import SALTVERSION %}
|
||||||
|
|
||||||
{% if HYPERVISORS %}
|
{% if HYPERVISORS %}
|
||||||
cloud_providers:
|
cloud_providers:
|
||||||
@@ -20,7 +21,7 @@ cloud_providers:
|
|||||||
- name: /etc/salt/cloud.providers.d/libvirt.conf
|
- name: /etc/salt/cloud.providers.d/libvirt.conf
|
||||||
- source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja
|
- source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja
|
||||||
- defaults:
|
- defaults:
|
||||||
HYPERVISORS: {{HYPERVISORS}}
|
HYPERVISORS: {{ HYPERVISORS }}
|
||||||
- template: jinja
|
- template: jinja
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
@@ -29,11 +30,17 @@ cloud_profiles:
|
|||||||
- name: /etc/salt/cloud.profiles.d/socloud.conf
|
- name: /etc/salt/cloud.profiles.d/socloud.conf
|
||||||
- source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja
|
- source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja
|
||||||
- defaults:
|
- defaults:
|
||||||
HYPERVISORS: {{HYPERVISORS}}
|
HYPERVISORS: {{ HYPERVISORS }}
|
||||||
MANAGERHOSTNAME: {{ grains.host }}
|
MANAGERHOSTNAME: {{ grains.host }}
|
||||||
MANAGERIP: {{ pillar.host.mainip }}
|
MANAGERIP: {{ pillar.host.mainip }}
|
||||||
|
SALTVERSION: {{ SALTVERSION }}
|
||||||
- template: jinja
|
- template: jinja
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
{% else %}
|
||||||
|
no_hypervisors_configured:
|
||||||
|
test.succeed_without_changes:
|
||||||
|
- name: no_hypervisors_configured
|
||||||
|
- comment: No hypervisors are configured
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -727,7 +727,8 @@ def check_hypervisor_disk_space(hypervisor: str, size_gb: int) -> Tuple[bool, Op
|
|||||||
result = local.cmd(
|
result = local.cmd(
|
||||||
hypervisor_minion,
|
hypervisor_minion,
|
||||||
'cmd.run',
|
'cmd.run',
|
||||||
["df -BG /nsm/libvirt/volumes | tail -1 | awk '{print $4}' | sed 's/G//'"]
|
["df -BG /nsm/libvirt/volumes | tail -1 | awk '{print $4}' | sed 's/G//'"],
|
||||||
|
kwarg={'python_shell': True}
|
||||||
)
|
)
|
||||||
|
|
||||||
if not result or hypervisor_minion not in result:
|
if not result or hypervisor_minion not in result:
|
||||||
|
|||||||
@@ -6,30 +6,6 @@ engines:
|
|||||||
interval: 60
|
interval: 60
|
||||||
- pillarWatch:
|
- pillarWatch:
|
||||||
fpa:
|
fpa:
|
||||||
- files:
|
|
||||||
- /opt/so/saltstack/local/pillar/idstools/soc_idstools.sls
|
|
||||||
- /opt/so/saltstack/local/pillar/idstools/adv_idstools.sls
|
|
||||||
pillar: idstools.config.ruleset
|
|
||||||
default: ETOPEN
|
|
||||||
actions:
|
|
||||||
from:
|
|
||||||
'*':
|
|
||||||
to:
|
|
||||||
'*':
|
|
||||||
- cmd.run:
|
|
||||||
cmd: /usr/sbin/so-rule-update
|
|
||||||
- files:
|
|
||||||
- /opt/so/saltstack/local/pillar/idstools/soc_idstools.sls
|
|
||||||
- /opt/so/saltstack/local/pillar/idstools/adv_idstools.sls
|
|
||||||
pillar: idstools.config.oinkcode
|
|
||||||
default: ''
|
|
||||||
actions:
|
|
||||||
from:
|
|
||||||
'*':
|
|
||||||
to:
|
|
||||||
'*':
|
|
||||||
- cmd.run:
|
|
||||||
cmd: /usr/sbin/so-rule-update
|
|
||||||
- files:
|
- files:
|
||||||
- /opt/so/saltstack/local/pillar/global/soc_global.sls
|
- /opt/so/saltstack/local/pillar/global/soc_global.sls
|
||||||
- /opt/so/saltstack/local/pillar/global/adv_global.sls
|
- /opt/so/saltstack/local/pillar/global/adv_global.sls
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched
|
# version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched
|
||||||
salt:
|
salt:
|
||||||
master:
|
master:
|
||||||
version: '3006.9'
|
version: '3006.16'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched
|
# version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched
|
||||||
salt:
|
salt:
|
||||||
minion:
|
minion:
|
||||||
version: '3006.9'
|
version: '3006.16'
|
||||||
check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default
|
check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#======================================================================================================================
|
#======================================================================================================================
|
||||||
set -o nounset # Treat unset variables as an error
|
set -o nounset # Treat unset variables as an error
|
||||||
|
|
||||||
__ScriptVersion="2025.02.24"
|
__ScriptVersion="2025.09.03"
|
||||||
__ScriptName="bootstrap-salt.sh"
|
__ScriptName="bootstrap-salt.sh"
|
||||||
|
|
||||||
__ScriptFullName="$0"
|
__ScriptFullName="$0"
|
||||||
@@ -48,6 +48,7 @@ __ScriptArgs="$*"
|
|||||||
# * BS_GENTOO_USE_BINHOST: If 1 add `--getbinpkg` to gentoo's emerge
|
# * BS_GENTOO_USE_BINHOST: If 1 add `--getbinpkg` to gentoo's emerge
|
||||||
# * BS_SALT_MASTER_ADDRESS: The IP or DNS name of the salt-master the minion should connect to
|
# * BS_SALT_MASTER_ADDRESS: The IP or DNS name of the salt-master the minion should connect to
|
||||||
# * BS_SALT_GIT_CHECKOUT_DIR: The directory where to clone Salt on git installations
|
# * BS_SALT_GIT_CHECKOUT_DIR: The directory where to clone Salt on git installations
|
||||||
|
# * BS_TMP_DIR: The directory to use for executing the installation (defaults to /tmp)
|
||||||
#======================================================================================================================
|
#======================================================================================================================
|
||||||
|
|
||||||
|
|
||||||
@@ -171,12 +172,12 @@ __check_config_dir() {
|
|||||||
|
|
||||||
case "$CC_DIR_NAME" in
|
case "$CC_DIR_NAME" in
|
||||||
http://*|https://*)
|
http://*|https://*)
|
||||||
__fetch_url "/tmp/${CC_DIR_BASE}" "${CC_DIR_NAME}"
|
__fetch_url "${_TMP_DIR}/${CC_DIR_BASE}" "${CC_DIR_NAME}"
|
||||||
CC_DIR_NAME="/tmp/${CC_DIR_BASE}"
|
CC_DIR_NAME="${_TMP_DIR}/${CC_DIR_BASE}"
|
||||||
;;
|
;;
|
||||||
ftp://*)
|
ftp://*)
|
||||||
__fetch_url "/tmp/${CC_DIR_BASE}" "${CC_DIR_NAME}"
|
__fetch_url "${_TMP_DIR}/${CC_DIR_BASE}" "${CC_DIR_NAME}"
|
||||||
CC_DIR_NAME="/tmp/${CC_DIR_BASE}"
|
CC_DIR_NAME="${_TMP_DIR}/${CC_DIR_BASE}"
|
||||||
;;
|
;;
|
||||||
*://*)
|
*://*)
|
||||||
echoerror "Unsupported URI scheme for $CC_DIR_NAME"
|
echoerror "Unsupported URI scheme for $CC_DIR_NAME"
|
||||||
@@ -194,22 +195,22 @@ __check_config_dir() {
|
|||||||
|
|
||||||
case "$CC_DIR_NAME" in
|
case "$CC_DIR_NAME" in
|
||||||
*.tgz|*.tar.gz)
|
*.tgz|*.tar.gz)
|
||||||
tar -zxf "${CC_DIR_NAME}" -C /tmp
|
tar -zxf "${CC_DIR_NAME}" -C ${_TMP_DIR}
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tgz")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tgz")
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.gz")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.gz")
|
||||||
CC_DIR_NAME="/tmp/${CC_DIR_BASE}"
|
CC_DIR_NAME="${_TMP_DIR}/${CC_DIR_BASE}"
|
||||||
;;
|
;;
|
||||||
*.tbz|*.tar.bz2)
|
*.tbz|*.tar.bz2)
|
||||||
tar -xjf "${CC_DIR_NAME}" -C /tmp
|
tar -xjf "${CC_DIR_NAME}" -C ${_TMP_DIR}
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tbz")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tbz")
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.bz2")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.bz2")
|
||||||
CC_DIR_NAME="/tmp/${CC_DIR_BASE}"
|
CC_DIR_NAME="${_TMP_DIR}/${CC_DIR_BASE}"
|
||||||
;;
|
;;
|
||||||
*.txz|*.tar.xz)
|
*.txz|*.tar.xz)
|
||||||
tar -xJf "${CC_DIR_NAME}" -C /tmp
|
tar -xJf "${CC_DIR_NAME}" -C ${_TMP_DIR}
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".txz")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".txz")
|
||||||
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.xz")
|
CC_DIR_BASE=$(basename "${CC_DIR_BASE}" ".tar.xz")
|
||||||
CC_DIR_NAME="/tmp/${CC_DIR_BASE}"
|
CC_DIR_NAME="${_TMP_DIR}/${CC_DIR_BASE}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -245,6 +246,7 @@ __check_unparsed_options() {
|
|||||||
#----------------------------------------------------------------------------------------------------------------------
|
#----------------------------------------------------------------------------------------------------------------------
|
||||||
_KEEP_TEMP_FILES=${BS_KEEP_TEMP_FILES:-$BS_FALSE}
|
_KEEP_TEMP_FILES=${BS_KEEP_TEMP_FILES:-$BS_FALSE}
|
||||||
_TEMP_CONFIG_DIR="null"
|
_TEMP_CONFIG_DIR="null"
|
||||||
|
_TMP_DIR=${BS_TMP_DIR:-"/tmp"}
|
||||||
_SALTSTACK_REPO_URL="https://github.com/saltstack/salt.git"
|
_SALTSTACK_REPO_URL="https://github.com/saltstack/salt.git"
|
||||||
_SALT_REPO_URL=${_SALTSTACK_REPO_URL}
|
_SALT_REPO_URL=${_SALTSTACK_REPO_URL}
|
||||||
_TEMP_KEYS_DIR="null"
|
_TEMP_KEYS_DIR="null"
|
||||||
@@ -281,7 +283,7 @@ _SIMPLIFY_VERSION=$BS_TRUE
|
|||||||
_LIBCLOUD_MIN_VERSION="0.14.0"
|
_LIBCLOUD_MIN_VERSION="0.14.0"
|
||||||
_EXTRA_PACKAGES=""
|
_EXTRA_PACKAGES=""
|
||||||
_HTTP_PROXY=""
|
_HTTP_PROXY=""
|
||||||
_SALT_GIT_CHECKOUT_DIR=${BS_SALT_GIT_CHECKOUT_DIR:-/tmp/git/salt}
|
_SALT_GIT_CHECKOUT_DIR=${BS_SALT_GIT_CHECKOUT_DIR:-${_TMP_DIR}/git/salt}
|
||||||
_NO_DEPS=$BS_FALSE
|
_NO_DEPS=$BS_FALSE
|
||||||
_FORCE_SHALLOW_CLONE=$BS_FALSE
|
_FORCE_SHALLOW_CLONE=$BS_FALSE
|
||||||
_DISABLE_SSL=$BS_FALSE
|
_DISABLE_SSL=$BS_FALSE
|
||||||
@@ -367,7 +369,7 @@ __usage() {
|
|||||||
also be specified. Salt installation will be ommitted, but some of the
|
also be specified. Salt installation will be ommitted, but some of the
|
||||||
dependencies could be installed to write configuration with -j or -J.
|
dependencies could be installed to write configuration with -j or -J.
|
||||||
-d Disables checking if Salt services are enabled to start on system boot.
|
-d Disables checking if Salt services are enabled to start on system boot.
|
||||||
You can also do this by touching /tmp/disable_salt_checks on the target
|
You can also do this by touching ${BS_TMP_DIR}/disable_salt_checks on the target
|
||||||
host. Default: \${BS_FALSE}
|
host. Default: \${BS_FALSE}
|
||||||
-D Show debug output
|
-D Show debug output
|
||||||
-f Force shallow cloning for git installations.
|
-f Force shallow cloning for git installations.
|
||||||
@@ -424,6 +426,9 @@ __usage() {
|
|||||||
-r Disable all repository configuration performed by this script. This
|
-r Disable all repository configuration performed by this script. This
|
||||||
option assumes all necessary repository configuration is already present
|
option assumes all necessary repository configuration is already present
|
||||||
on the system.
|
on the system.
|
||||||
|
-T If set this overrides the use of /tmp for script execution. This is
|
||||||
|
to allow for systems in which noexec is applied to temp filesystem mounts
|
||||||
|
for security reasons
|
||||||
-U If set, fully upgrade the system prior to bootstrapping Salt
|
-U If set, fully upgrade the system prior to bootstrapping Salt
|
||||||
-v Display script version
|
-v Display script version
|
||||||
-V Install Salt into virtualenv
|
-V Install Salt into virtualenv
|
||||||
@@ -436,7 +441,7 @@ __usage() {
|
|||||||
EOT
|
EOT
|
||||||
} # ---------- end of function __usage ----------
|
} # ---------- end of function __usage ----------
|
||||||
|
|
||||||
while getopts ':hvnDc:g:Gx:k:s:MSWNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:aqQ' opt
|
while getopts ':hvnDc:g:Gx:k:s:MSWNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:T:aqQ' opt
|
||||||
do
|
do
|
||||||
case "${opt}" in
|
case "${opt}" in
|
||||||
|
|
||||||
@@ -478,6 +483,7 @@ do
|
|||||||
a ) _PIP_ALL=$BS_TRUE ;;
|
a ) _PIP_ALL=$BS_TRUE ;;
|
||||||
r ) _DISABLE_REPOS=$BS_TRUE ;;
|
r ) _DISABLE_REPOS=$BS_TRUE ;;
|
||||||
R ) _CUSTOM_REPO_URL=$OPTARG ;;
|
R ) _CUSTOM_REPO_URL=$OPTARG ;;
|
||||||
|
T ) _TMP_DIR="$OPTARG" ;;
|
||||||
J ) _CUSTOM_MASTER_CONFIG=$OPTARG ;;
|
J ) _CUSTOM_MASTER_CONFIG=$OPTARG ;;
|
||||||
j ) _CUSTOM_MINION_CONFIG=$OPTARG ;;
|
j ) _CUSTOM_MINION_CONFIG=$OPTARG ;;
|
||||||
q ) _QUIET_GIT_INSTALLATION=$BS_TRUE ;;
|
q ) _QUIET_GIT_INSTALLATION=$BS_TRUE ;;
|
||||||
@@ -495,10 +501,10 @@ done
|
|||||||
shift $((OPTIND-1))
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
# Define our logging file and pipe paths
|
# Define our logging file and pipe paths
|
||||||
LOGFILE="/tmp/$( echo "$__ScriptName" | sed s/.sh/.log/g )"
|
LOGFILE="${_TMP_DIR}/$( echo "$__ScriptName" | sed s/.sh/.log/g )"
|
||||||
LOGPIPE="/tmp/$( echo "$__ScriptName" | sed s/.sh/.logpipe/g )"
|
LOGPIPE="${_TMP_DIR}/$( echo "$__ScriptName" | sed s/.sh/.logpipe/g )"
|
||||||
# Ensure no residual pipe exists
|
# Ensure no residual pipe exists
|
||||||
rm "$LOGPIPE" 2>/dev/null
|
rm -f "$LOGPIPE" 2>/dev/null
|
||||||
|
|
||||||
# Create our logging pipe
|
# Create our logging pipe
|
||||||
# On FreeBSD we have to use mkfifo instead of mknod
|
# On FreeBSD we have to use mkfifo instead of mknod
|
||||||
@@ -534,7 +540,7 @@ exec 2>"$LOGPIPE"
|
|||||||
# 14 SIGALRM
|
# 14 SIGALRM
|
||||||
# 15 SIGTERM
|
# 15 SIGTERM
|
||||||
#----------------------------------------------------------------------------------------------------------------------
|
#----------------------------------------------------------------------------------------------------------------------
|
||||||
APT_ERR=$(mktemp /tmp/apt_error.XXXXXX)
|
APT_ERR=$(mktemp ${_TMP_DIR}/apt_error.XXXXXX)
|
||||||
__exit_cleanup() {
|
__exit_cleanup() {
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
|
|
||||||
@@ -927,6 +933,11 @@ if [ -d "${_VIRTUALENV_DIR}" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Make sure the designated temp directory exists
|
||||||
|
if [ ! -d "${_TMP_DIR}" ]; then
|
||||||
|
mkdir -p "${_TMP_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
#--- FUNCTION -------------------------------------------------------------------------------------------------------
|
#--- FUNCTION -------------------------------------------------------------------------------------------------------
|
||||||
# NAME: __fetch_url
|
# NAME: __fetch_url
|
||||||
# DESCRIPTION: Retrieves a URL and writes it to a given path
|
# DESCRIPTION: Retrieves a URL and writes it to a given path
|
||||||
@@ -1941,11 +1952,6 @@ __wait_for_apt(){
|
|||||||
# Timeout set at 15 minutes
|
# Timeout set at 15 minutes
|
||||||
WAIT_TIMEOUT=900
|
WAIT_TIMEOUT=900
|
||||||
|
|
||||||
## see if sync'ing the clocks helps
|
|
||||||
if [ -f /usr/sbin/hwclock ]; then
|
|
||||||
/usr/sbin/hwclock -s
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run our passed in apt command
|
# Run our passed in apt command
|
||||||
"${@}" 2>"$APT_ERR"
|
"${@}" 2>"$APT_ERR"
|
||||||
APT_RETURN=$?
|
APT_RETURN=$?
|
||||||
@@ -1996,14 +2002,14 @@ __apt_get_upgrade_noinput() {
|
|||||||
#----------------------------------------------------------------------------------------------------------------------
|
#----------------------------------------------------------------------------------------------------------------------
|
||||||
__temp_gpg_pub() {
|
__temp_gpg_pub() {
|
||||||
if __check_command_exists mktemp; then
|
if __check_command_exists mktemp; then
|
||||||
tempfile="$(mktemp /tmp/salt-gpg-XXXXXXXX.pub 2>/dev/null)"
|
tempfile="$(mktemp ${_TMP_DIR}/salt-gpg-XXXXXXXX.pub 2>/dev/null)"
|
||||||
|
|
||||||
if [ -z "$tempfile" ]; then
|
if [ -z "$tempfile" ]; then
|
||||||
echoerror "Failed to create temporary file in /tmp"
|
echoerror "Failed to create temporary file in ${_TMP_DIR}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
tempfile="/tmp/salt-gpg-$$.pub"
|
tempfile="${_TMP_DIR}/salt-gpg-$$.pub"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $tempfile
|
echo $tempfile
|
||||||
@@ -2043,7 +2049,7 @@ __rpm_import_gpg() {
|
|||||||
__fetch_url "$tempfile" "$url" || return 1
|
__fetch_url "$tempfile" "$url" || return 1
|
||||||
|
|
||||||
# At least on CentOS 8, a missing newline at the end causes:
|
# At least on CentOS 8, a missing newline at the end causes:
|
||||||
# error: /tmp/salt-gpg-n1gKUb1u.pub: key 1 not an armored public key.
|
# error: ${_TMP_DIR}/salt-gpg-n1gKUb1u.pub: key 1 not an armored public key.
|
||||||
# shellcheck disable=SC1003,SC2086
|
# shellcheck disable=SC1003,SC2086
|
||||||
sed -i -e '$a\' $tempfile
|
sed -i -e '$a\' $tempfile
|
||||||
|
|
||||||
@@ -2109,7 +2115,7 @@ __git_clone_and_checkout() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
__SALT_GIT_CHECKOUT_PARENT_DIR=$(dirname "${_SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)
|
__SALT_GIT_CHECKOUT_PARENT_DIR=$(dirname "${_SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)
|
||||||
__SALT_GIT_CHECKOUT_PARENT_DIR="${__SALT_GIT_CHECKOUT_PARENT_DIR:-/tmp/git}"
|
__SALT_GIT_CHECKOUT_PARENT_DIR="${__SALT_GIT_CHECKOUT_PARENT_DIR:-${_TMP_DIR}/git}"
|
||||||
__SALT_CHECKOUT_REPONAME="$(basename "${_SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)"
|
__SALT_CHECKOUT_REPONAME="$(basename "${_SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)"
|
||||||
__SALT_CHECKOUT_REPONAME="${__SALT_CHECKOUT_REPONAME:-salt}"
|
__SALT_CHECKOUT_REPONAME="${__SALT_CHECKOUT_REPONAME:-salt}"
|
||||||
[ -d "${__SALT_GIT_CHECKOUT_PARENT_DIR}" ] || mkdir "${__SALT_GIT_CHECKOUT_PARENT_DIR}"
|
[ -d "${__SALT_GIT_CHECKOUT_PARENT_DIR}" ] || mkdir "${__SALT_GIT_CHECKOUT_PARENT_DIR}"
|
||||||
@@ -2162,7 +2168,7 @@ __git_clone_and_checkout() {
|
|||||||
|
|
||||||
if [ "$__SHALLOW_CLONE" -eq $BS_TRUE ]; then
|
if [ "$__SHALLOW_CLONE" -eq $BS_TRUE ]; then
|
||||||
# Let's try 'treeless' cloning to speed up. Treeless cloning omits trees and blobs ('files')
|
# Let's try 'treeless' cloning to speed up. Treeless cloning omits trees and blobs ('files')
|
||||||
# but includes metadata (commit history, tags, branches etc.
|
# but includes metadata (commit history, tags, branches etc.
|
||||||
# Test for "--filter" option introduced in git 2.19, the minimal version of git where the treeless
|
# Test for "--filter" option introduced in git 2.19, the minimal version of git where the treeless
|
||||||
# cloning we need actually works
|
# cloning we need actually works
|
||||||
if [ "$(git clone 2>&1 | grep 'filter')" != "" ]; then
|
if [ "$(git clone 2>&1 | grep 'filter')" != "" ]; then
|
||||||
@@ -2390,14 +2396,14 @@ __overwriteconfig() {
|
|||||||
|
|
||||||
# Make a tempfile to dump any python errors into.
|
# Make a tempfile to dump any python errors into.
|
||||||
if __check_command_exists mktemp; then
|
if __check_command_exists mktemp; then
|
||||||
tempfile="$(mktemp /tmp/salt-config-XXXXXXXX 2>/dev/null)"
|
tempfile="$(mktemp ${_TMP_DIR}/salt-config-XXXXXXXX 2>/dev/null)"
|
||||||
|
|
||||||
if [ -z "$tempfile" ]; then
|
if [ -z "$tempfile" ]; then
|
||||||
echoerror "Failed to create temporary file in /tmp"
|
echoerror "Failed to create temporary file in ${_TMP_DIR}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
tempfile="/tmp/salt-config-$$"
|
tempfile="${_TMP_DIR}/salt-config-$$"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$_PY_EXE" ]; then
|
if [ -n "$_PY_EXE" ]; then
|
||||||
@@ -2760,8 +2766,8 @@ __install_salt_from_repo() {
|
|||||||
echoinfo "Installing salt using ${_py_exe}, $(${_py_exe} --version)"
|
echoinfo "Installing salt using ${_py_exe}, $(${_py_exe} --version)"
|
||||||
cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1
|
cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1
|
||||||
|
|
||||||
mkdir -p /tmp/git/deps
|
mkdir -p ${_TMP_DIR}/git/deps
|
||||||
echodebug "Created directory /tmp/git/deps"
|
echodebug "Created directory ${_TMP_DIR}/git/deps"
|
||||||
|
|
||||||
if [ ${DISTRO_NAME_L} = "ubuntu" ] && [ "$DISTRO_MAJOR_VERSION" -eq 22 ]; then
|
if [ ${DISTRO_NAME_L} = "ubuntu" ] && [ "$DISTRO_MAJOR_VERSION" -eq 22 ]; then
|
||||||
echodebug "Ubuntu 22.04 has problem with base.txt requirements file, not parsing sys_platform == 'win32', upgrading from default pip works"
|
echodebug "Ubuntu 22.04 has problem with base.txt requirements file, not parsing sys_platform == 'win32', upgrading from default pip works"
|
||||||
@@ -2774,7 +2780,7 @@ __install_salt_from_repo() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f /tmp/git/deps/*
|
rm -f ${_TMP_DIR}/git/deps/*
|
||||||
|
|
||||||
echodebug "Installing Salt requirements from PyPi, ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} -r requirements/static/ci/py${_py_version}/linux.txt"
|
echodebug "Installing Salt requirements from PyPi, ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} -r requirements/static/ci/py${_py_version}/linux.txt"
|
||||||
${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} -r "requirements/static/ci/py${_py_version}/linux.txt"
|
${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} -r "requirements/static/ci/py${_py_version}/linux.txt"
|
||||||
@@ -2799,7 +2805,7 @@ __install_salt_from_repo() {
|
|||||||
|
|
||||||
echodebug "Running '${_py_exe} setup.py --salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} bdist_wheel'"
|
echodebug "Running '${_py_exe} setup.py --salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} bdist_wheel'"
|
||||||
${_py_exe} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" bdist_wheel || return 1
|
${_py_exe} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" bdist_wheel || return 1
|
||||||
mv dist/salt*.whl /tmp/git/deps/ || return 1
|
mv dist/salt*.whl ${_TMP_DIR}/git/deps/ || return 1
|
||||||
|
|
||||||
cd "${__SALT_GIT_CHECKOUT_PARENT_DIR}" || return 1
|
cd "${__SALT_GIT_CHECKOUT_PARENT_DIR}" || return 1
|
||||||
|
|
||||||
@@ -2813,14 +2819,14 @@ __install_salt_from_repo() {
|
|||||||
${_pip_cmd} install --force-reinstall --break-system-packages "${_arch_dep}"
|
${_pip_cmd} install --force-reinstall --break-system-packages "${_arch_dep}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} /tmp/git/deps/salt*.whl'"
|
echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl'"
|
||||||
|
|
||||||
echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} /tmp/git/deps/salt*.whl"
|
echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl"
|
||||||
|
|
||||||
${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \
|
${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \
|
||||||
${_PIP_INSTALL_ARGS} \
|
${_PIP_INSTALL_ARGS} \
|
||||||
--global-option="--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \
|
--global-option="--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \
|
||||||
/tmp/git/deps/salt*.whl || return 1
|
${_TMP_DIR}/git/deps/salt*.whl || return 1
|
||||||
|
|
||||||
echoinfo "Checking if Salt can be imported using ${_py_exe}"
|
echoinfo "Checking if Salt can be imported using ${_py_exe}"
|
||||||
CHECK_SALT_SCRIPT=$(cat << EOM
|
CHECK_SALT_SCRIPT=$(cat << EOM
|
||||||
@@ -6295,8 +6301,8 @@ __get_packagesite_onedir_latest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__install_saltstack_photon_onedir_repository() {
|
__install_saltstack_vmware_photon_os_onedir_repository() {
|
||||||
echodebug "__install_saltstack_photon_onedir_repository() entry"
|
echodebug "__install_saltstack_vmware_photon_os_onedir_repository() entry"
|
||||||
|
|
||||||
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
||||||
echoerror "Python version is no longer supported, only Python 3"
|
echoerror "Python version is no longer supported, only Python 3"
|
||||||
@@ -6376,8 +6382,8 @@ __install_saltstack_photon_onedir_repository() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_deps() {
|
install_vmware_photon_os_deps() {
|
||||||
echodebug "install_photon_deps() entry"
|
echodebug "install_vmware_photon_os_deps() entry"
|
||||||
|
|
||||||
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
||||||
echoerror "Python version is no longer supported, only Python 3"
|
echoerror "Python version is no longer supported, only Python 3"
|
||||||
@@ -6406,8 +6412,8 @@ install_photon_deps() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_stable_post() {
|
install_vmware_photon_os_stable_post() {
|
||||||
echodebug "install_photon_stable_post() entry"
|
echodebug "install_vmware_photon_os_stable_post() entry"
|
||||||
|
|
||||||
for fname in api master minion syndic; do
|
for fname in api master minion syndic; do
|
||||||
# Skip salt-api since the service should be opt-in and not necessarily started on boot
|
# Skip salt-api since the service should be opt-in and not necessarily started on boot
|
||||||
@@ -6424,8 +6430,8 @@ install_photon_stable_post() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_git_deps() {
|
install_vmware_photon_os_git_deps() {
|
||||||
echodebug "install_photon_git_deps() entry"
|
echodebug "install_vmware_photon_os_git_deps() entry"
|
||||||
|
|
||||||
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then
|
||||||
echoerror "Python version is no longer supported, only Python 3"
|
echoerror "Python version is no longer supported, only Python 3"
|
||||||
@@ -6463,7 +6469,7 @@ install_photon_git_deps() {
|
|||||||
|
|
||||||
__PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc glibc-devel linux-devel.x86_64 cython${PY_PKG_VER}"
|
__PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc glibc-devel linux-devel.x86_64 cython${PY_PKG_VER}"
|
||||||
|
|
||||||
echodebug "install_photon_git_deps() distro major version, ${DISTRO_MAJOR_VERSION}"
|
echodebug "install_vmware_photon_os_git_deps() distro major version, ${DISTRO_MAJOR_VERSION}"
|
||||||
|
|
||||||
## Photon 5 container is missing systemd on default installation
|
## Photon 5 container is missing systemd on default installation
|
||||||
if [ "${DISTRO_MAJOR_VERSION}" -lt 5 ]; then
|
if [ "${DISTRO_MAJOR_VERSION}" -lt 5 ]; then
|
||||||
@@ -6489,8 +6495,8 @@ install_photon_git_deps() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_git() {
|
install_vmware_photon_os_git() {
|
||||||
echodebug "install_photon_git() entry"
|
echodebug "install_vmware_photon_os_git() entry"
|
||||||
|
|
||||||
if [ "${_PY_EXE}" != "" ]; then
|
if [ "${_PY_EXE}" != "" ]; then
|
||||||
_PYEXE=${_PY_EXE}
|
_PYEXE=${_PY_EXE}
|
||||||
@@ -6500,7 +6506,7 @@ install_photon_git() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install_photon_git_deps
|
install_vmware_photon_os_git_deps
|
||||||
|
|
||||||
if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then
|
if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then
|
||||||
${_PYEXE} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1
|
${_PYEXE} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1
|
||||||
@@ -6510,8 +6516,8 @@ install_photon_git() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_git_post() {
|
install_vmware_photon_os_git_post() {
|
||||||
echodebug "install_photon_git_post() entry"
|
echodebug "install_vmware_photon_os_git_post() entry"
|
||||||
|
|
||||||
for fname in api master minion syndic; do
|
for fname in api master minion syndic; do
|
||||||
# Skip if not meant to be installed
|
# Skip if not meant to be installed
|
||||||
@@ -6543,9 +6549,9 @@ install_photon_git_post() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_restart_daemons() {
|
install_vmware_photon_os_restart_daemons() {
|
||||||
[ "$_START_DAEMONS" -eq $BS_FALSE ] && return
|
[ "$_START_DAEMONS" -eq $BS_FALSE ] && return
|
||||||
echodebug "install_photon_restart_daemons() entry"
|
echodebug "install_vmware_photon_os_restart_daemons() entry"
|
||||||
|
|
||||||
|
|
||||||
for fname in api master minion syndic; do
|
for fname in api master minion syndic; do
|
||||||
@@ -6567,8 +6573,8 @@ install_photon_restart_daemons() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_check_services() {
|
install_vmware_photon_os_check_services() {
|
||||||
echodebug "install_photon_check_services() entry"
|
echodebug "install_vmware_photon_os_check_services() entry"
|
||||||
|
|
||||||
for fname in api master minion syndic; do
|
for fname in api master minion syndic; do
|
||||||
# Skip salt-api since the service should be opt-in and not necessarily started on boot
|
# Skip salt-api since the service should be opt-in and not necessarily started on boot
|
||||||
@@ -6585,8 +6591,8 @@ install_photon_check_services() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_onedir_deps() {
|
install_vmware_photon_os_onedir_deps() {
|
||||||
echodebug "install_photon_onedir_deps() entry"
|
echodebug "install_vmware_photon_os_onedir_deps() entry"
|
||||||
|
|
||||||
|
|
||||||
if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then
|
if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then
|
||||||
@@ -6600,17 +6606,17 @@ install_photon_onedir_deps() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then
|
if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then
|
||||||
__install_saltstack_photon_onedir_repository || return 1
|
__install_saltstack_vmware_photon_os_onedir_repository || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If -R was passed, we need to configure custom repo url with rsync-ed packages
|
# If -R was passed, we need to configure custom repo url with rsync-ed packages
|
||||||
# Which was handled in __install_saltstack_rhel_repository buu that hanlded old-stable which is for
|
# Which was handled in __install_saltstack_rhel_repository buu that hanlded old-stable which is for
|
||||||
# releases which are End-Of-Life. This call has its own check in case -r was passed without -R.
|
# releases which are End-Of-Life. This call has its own check in case -r was passed without -R.
|
||||||
if [ "$_CUSTOM_REPO_URL" != "null" ]; then
|
if [ "$_CUSTOM_REPO_URL" != "null" ]; then
|
||||||
__install_saltstack_photon_onedir_repository || return 1
|
__install_saltstack_vmware_photon_os_onedir_repository || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
__PACKAGES="procps-ng sudo shadow"
|
__PACKAGES="procps-ng sudo shadow wget"
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
__tdnf_install_noinput ${__PACKAGES} || return 1
|
__tdnf_install_noinput ${__PACKAGES} || return 1
|
||||||
@@ -6626,9 +6632,9 @@ install_photon_onedir_deps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
install_photon_onedir() {
|
install_vmware_photon_os_onedir() {
|
||||||
|
|
||||||
echodebug "install_photon_onedir() entry"
|
echodebug "install_vmware_photon_os_onedir() entry"
|
||||||
|
|
||||||
STABLE_REV=$ONEDIR_REV
|
STABLE_REV=$ONEDIR_REV
|
||||||
_GENERIC_PKG_VERSION=""
|
_GENERIC_PKG_VERSION=""
|
||||||
@@ -6672,9 +6678,9 @@ install_photon_onedir() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
install_photon_onedir_post() {
|
install_vmware_photon_os_onedir_post() {
|
||||||
STABLE_REV=$ONEDIR_REV
|
STABLE_REV=$ONEDIR_REV
|
||||||
install_photon_stable_post || return 1
|
install_vmware_photon_os_stable_post || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -7797,7 +7803,7 @@ install_macosx_git_deps() {
|
|||||||
export PATH=/usr/local/bin:$PATH
|
export PATH=/usr/local/bin:$PATH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
__fetch_url "/tmp/get-pip.py" "https://bootstrap.pypa.io/get-pip.py" || return 1
|
__fetch_url "${_TMP_DIR}/get-pip.py" "https://bootstrap.pypa.io/get-pip.py" || return 1
|
||||||
|
|
||||||
if [ -n "$_PY_EXE" ]; then
|
if [ -n "$_PY_EXE" ]; then
|
||||||
_PYEXE="${_PY_EXE}"
|
_PYEXE="${_PY_EXE}"
|
||||||
@@ -7807,7 +7813,7 @@ install_macosx_git_deps() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Install PIP
|
# Install PIP
|
||||||
$_PYEXE /tmp/get-pip.py || return 1
|
$_PYEXE ${_TMP_DIR}/get-pip.py || return 1
|
||||||
|
|
||||||
# shellcheck disable=SC2119
|
# shellcheck disable=SC2119
|
||||||
__git_clone_and_checkout || return 1
|
__git_clone_and_checkout || return 1
|
||||||
@@ -7819,9 +7825,9 @@ install_macosx_stable() {
|
|||||||
|
|
||||||
install_macosx_stable_deps || return 1
|
install_macosx_stable_deps || return 1
|
||||||
|
|
||||||
__fetch_url "/tmp/${PKG}" "${SALTPKGCONFURL}" || return 1
|
__fetch_url "${_TMP_DIR}/${PKG}" "${SALTPKGCONFURL}" || return 1
|
||||||
|
|
||||||
/usr/sbin/installer -pkg "/tmp/${PKG}" -target / || return 1
|
/usr/sbin/installer -pkg "${_TMP_DIR}/${PKG}" -target / || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -7830,9 +7836,9 @@ install_macosx_onedir() {
|
|||||||
|
|
||||||
install_macosx_onedir_deps || return 1
|
install_macosx_onedir_deps || return 1
|
||||||
|
|
||||||
__fetch_url "/tmp/${PKG}" "${SALTPKGCONFURL}" || return 1
|
__fetch_url "${_TMP_DIR}/${PKG}" "${SALTPKGCONFURL}" || return 1
|
||||||
|
|
||||||
/usr/sbin/installer -pkg "/tmp/${PKG}" -target / || return 1
|
/usr/sbin/installer -pkg "${_TMP_DIR}/${PKG}" -target / || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ sensoroni:
|
|||||||
sensoronikey:
|
sensoronikey:
|
||||||
soc_host:
|
soc_host:
|
||||||
suripcap:
|
suripcap:
|
||||||
pcapMaxCount: 999999
|
pcapMaxCount: 100000
|
||||||
analyzers:
|
analyzers:
|
||||||
echotrail:
|
echotrail:
|
||||||
base_url: https://api.echotrail.io/insights/
|
base_url: https://api.echotrail.io/insights/
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ socsensoronirepos:
|
|||||||
- mode: 775
|
- mode: 775
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
|
|
||||||
create_custom_local_yara_repo_template:
|
create_custom_local_yara_repo_template:
|
||||||
git.present:
|
git.present:
|
||||||
- name: /nsm/rules/custom-local-repos/local-yara
|
- name: /nsm/rules/custom-local-repos/local-yara
|
||||||
@@ -249,6 +248,39 @@ add_readme_custom_local_sigma_repo_template:
|
|||||||
- context:
|
- context:
|
||||||
repo_type: "sigma"
|
repo_type: "sigma"
|
||||||
|
|
||||||
|
create_custom_local_suricata_repo_template:
|
||||||
|
git.present:
|
||||||
|
- name: /nsm/rules/custom-local-repos/local-suricata
|
||||||
|
- bare: False
|
||||||
|
- force: True
|
||||||
|
|
||||||
|
add_readme_custom_local_suricata_repo_template:
|
||||||
|
file.managed:
|
||||||
|
- name: /nsm/rules/custom-local-repos/local-suricata/README
|
||||||
|
- source: salt://soc/files/soc/detections_custom_repo_template_readme.jinja
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- template: jinja
|
||||||
|
- context:
|
||||||
|
repo_type: "suricata"
|
||||||
|
|
||||||
|
etpro_airgap_folder:
|
||||||
|
file.directory:
|
||||||
|
- name: /nsm/rules/custom-local-repos/local-etpro-suricata
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
add_readme_etpro_airgap_template:
|
||||||
|
file.managed:
|
||||||
|
- name: /nsm/rules/custom-local-repos/local-etpro-suricata/README
|
||||||
|
- source: salt://soc/files/soc/detections_custom_repo_template_readme.jinja
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- template: jinja
|
||||||
|
- context:
|
||||||
|
repo_type: "suricata-etpro"
|
||||||
|
|
||||||
socore_own_custom_repos:
|
socore_own_custom_repos:
|
||||||
file.directory:
|
file.directory:
|
||||||
- name: /nsm/rules/custom-local-repos/
|
- name: /nsm/rules/custom-local-repos/
|
||||||
|
|||||||
@@ -1364,6 +1364,8 @@ soc:
|
|||||||
cases: soc
|
cases: soc
|
||||||
filedatastore:
|
filedatastore:
|
||||||
jobDir: jobs
|
jobDir: jobs
|
||||||
|
retryFailureIntervalMs: 600000
|
||||||
|
retryFailureMaxAttempts: 5
|
||||||
kratos:
|
kratos:
|
||||||
hostUrl:
|
hostUrl:
|
||||||
hydra:
|
hydra:
|
||||||
@@ -1561,12 +1563,106 @@ soc:
|
|||||||
disableRegex: []
|
disableRegex: []
|
||||||
enableRegex: []
|
enableRegex: []
|
||||||
failAfterConsecutiveErrorCount: 10
|
failAfterConsecutiveErrorCount: 10
|
||||||
communityRulesFile: /nsm/rules/suricata/emerging-all.rules
|
|
||||||
rulesFingerprintFile: /opt/sensoroni/fingerprints/emerging-all.fingerprint
|
rulesFingerprintFile: /opt/sensoroni/fingerprints/emerging-all.fingerprint
|
||||||
stateFilePath: /opt/sensoroni/fingerprints/suricataengine.state
|
stateFilePath: /opt/sensoroni/fingerprints/suricataengine.state
|
||||||
integrityCheckFrequencySeconds: 1200
|
integrityCheckFrequencySeconds: 1200
|
||||||
ignoredSidRanges:
|
ignoredSidRanges:
|
||||||
- '1100000-1101000'
|
- '1100000-1101000'
|
||||||
|
rulesetSources:
|
||||||
|
default:
|
||||||
|
- name: Emerging-Threats
|
||||||
|
description: "Emerging Threats ruleset - To enable ET Pro, enter your license key below. Leave empty for ET Open (free) rules."
|
||||||
|
licenseKey: ""
|
||||||
|
enabled: true
|
||||||
|
sourceType: url
|
||||||
|
sourcePath: 'https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz'
|
||||||
|
urlHash: "https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz.md5"
|
||||||
|
license: "BSD"
|
||||||
|
excludeFiles:
|
||||||
|
- "*deleted*"
|
||||||
|
- "*retired*"
|
||||||
|
proxyURL: ""
|
||||||
|
proxyUsername: ""
|
||||||
|
proxyPassword: ""
|
||||||
|
proxyCACert: ""
|
||||||
|
insecureSkipVerify: false
|
||||||
|
readOnly: true
|
||||||
|
deleteUnreferenced: true
|
||||||
|
- name: ABUSECH-SSLBL
|
||||||
|
deleteUnreferenced: true
|
||||||
|
description: 'Abuse.ch SSL Blacklist'
|
||||||
|
enabled: false
|
||||||
|
license: CC0-1.0
|
||||||
|
readOnly: true
|
||||||
|
sourcePath: https://sslbl.abuse.ch/blacklist/sslblacklist_tls_cert.tar.gz
|
||||||
|
sourceType: url
|
||||||
|
- name: local-rules
|
||||||
|
description: "Local rules from files (*.rules) in a directory on the filesystem"
|
||||||
|
license: "custom"
|
||||||
|
sourceType: directory
|
||||||
|
sourcePath: /nsm/rules/custom-local-repos/local-suricata
|
||||||
|
readOnly: false
|
||||||
|
deleteUnreferenced: false
|
||||||
|
enabled: true
|
||||||
|
- name: SO_FILTERS
|
||||||
|
deleteUnreferenced: true
|
||||||
|
description: Filter rules for when Suricata is set as the metadata engine
|
||||||
|
enabled: false
|
||||||
|
license: Elastic-2.0
|
||||||
|
readOnly: true
|
||||||
|
sourcePath: /nsm/rules/suricata/so_filters.rules
|
||||||
|
sourceType: directory
|
||||||
|
- name: SO_EXTRACTIONS
|
||||||
|
description: Extraction rules for when Suricata is set as the metadata engine
|
||||||
|
deleteUnreferenced: true
|
||||||
|
enabled: false
|
||||||
|
license: Elastic-2.0
|
||||||
|
readOnly: true
|
||||||
|
sourcePath: /nsm/rules/suricata/so_extraction.rules
|
||||||
|
sourceType: directory
|
||||||
|
airgap:
|
||||||
|
- name: Emerging-Threats
|
||||||
|
description: "Emerging Threats ruleset - To enable ET Pro, enter your license key below. Leave empty for ET Open (free) rules."
|
||||||
|
licenseKey: ""
|
||||||
|
enabled: true
|
||||||
|
sourceType: url
|
||||||
|
sourcePath: 'https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz'
|
||||||
|
urlHash: "https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz.md5"
|
||||||
|
license: "BSD"
|
||||||
|
excludeFiles:
|
||||||
|
- "*deleted*"
|
||||||
|
- "*retired*"
|
||||||
|
proxyURL: ""
|
||||||
|
proxyUsername: ""
|
||||||
|
proxyPassword: ""
|
||||||
|
proxyCACert: ""
|
||||||
|
insecureSkipVerify: false
|
||||||
|
readOnly: true
|
||||||
|
deleteUnreferenced: true
|
||||||
|
- name: local-rules
|
||||||
|
description: "Local rules from files (*.rules) in a directory on the filesystem"
|
||||||
|
license: "custom"
|
||||||
|
sourceType: directory
|
||||||
|
sourcePath: /nsm/rules/custom-local-repos/local-suricata
|
||||||
|
readOnly: false
|
||||||
|
deleteUnreferenced: false
|
||||||
|
enabled: true
|
||||||
|
- name: SO_FILTERS
|
||||||
|
deleteUnreferenced: true
|
||||||
|
description: Filter rules for when Suricata is set as the metadata engine
|
||||||
|
enabled: false
|
||||||
|
license: Elastic-2.0
|
||||||
|
readOnly: true
|
||||||
|
sourcePath: /nsm/rules/suricata/so_filters.rules
|
||||||
|
sourceType: directory
|
||||||
|
- name: SO_EXTRACTIONS
|
||||||
|
description: Extraction rules for when Suricata is set as the metadata engine
|
||||||
|
deleteUnreferenced: true
|
||||||
|
enabled: false
|
||||||
|
license: Elastic-2.0
|
||||||
|
readOnly: true
|
||||||
|
sourcePath: /nsm/rules/suricata/so_extraction.rules
|
||||||
|
sourceType: directory
|
||||||
navigator:
|
navigator:
|
||||||
intervalMinutes: 30
|
intervalMinutes: 30
|
||||||
outputPath: /opt/sensoroni/navigator
|
outputPath: /opt/sensoroni/navigator
|
||||||
@@ -1744,7 +1840,7 @@ soc:
|
|||||||
showSubtitle: true
|
showSubtitle: true
|
||||||
- name: DPD
|
- name: DPD
|
||||||
description: Dynamic Protocol Detection errors
|
description: Dynamic Protocol Detection errors
|
||||||
query: 'tags:dpd | groupby error.reason'
|
query: '(tags:dpd OR tags:analyzer) | groupby error.reason'
|
||||||
showSubtitle: true
|
showSubtitle: true
|
||||||
- name: Files
|
- name: Files
|
||||||
description: Files grouped by mimetype
|
description: Files grouped by mimetype
|
||||||
@@ -2010,7 +2106,7 @@ soc:
|
|||||||
query: 'tags:dns | groupby dns.query.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby dns.query.type_name | groupby dns.response.code_name | groupby dns.answers.name | groupby destination.as.organization.name'
|
query: 'tags:dns | groupby dns.query.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby dns.query.type_name | groupby dns.response.code_name | groupby dns.answers.name | groupby destination.as.organization.name'
|
||||||
- name: DPD
|
- name: DPD
|
||||||
description: DPD (Dynamic Protocol Detection) errors
|
description: DPD (Dynamic Protocol Detection) errors
|
||||||
query: 'tags:dpd | groupby error.reason | groupby -sankey error.reason source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby destination.as.organization.name'
|
query: '(tags:dpd OR tags:analyzer) | groupby error.reason | groupby -sankey error.reason source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby destination.as.organization.name'
|
||||||
- name: Files
|
- name: Files
|
||||||
description: Files seen in network traffic
|
description: Files seen in network traffic
|
||||||
query: 'tags:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination.as.organization.name'
|
query: 'tags:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination.as.organization.name'
|
||||||
@@ -2552,9 +2648,32 @@ soc:
|
|||||||
assistant:
|
assistant:
|
||||||
enabled: false
|
enabled: false
|
||||||
investigationPrompt: Investigate Alert ID {socId}
|
investigationPrompt: Investigate Alert ID {socId}
|
||||||
contextLimitSmall: 200000
|
compressContextPrompt: Summarize the conversation for context compaction
|
||||||
contextLimitLarge: 1000000
|
|
||||||
thresholdColorRatioLow: 0.5
|
thresholdColorRatioLow: 0.5
|
||||||
thresholdColorRatioMed: 0.75
|
thresholdColorRatioMed: 0.75
|
||||||
thresholdColorRatioMax: 1
|
thresholdColorRatioMax: 1
|
||||||
lowBalanceColorAlert: 500000
|
availableModels:
|
||||||
|
- id: sonnet-4
|
||||||
|
displayName: Claude Sonnet 4
|
||||||
|
contextLimitSmall: 200000
|
||||||
|
contextLimitLarge: 1000000
|
||||||
|
lowBalanceColorAlert: 500000
|
||||||
|
enabled: true
|
||||||
|
- id: sonnet-4.5
|
||||||
|
displayName: Claude Sonnet 4.5
|
||||||
|
contextLimitSmall: 200000
|
||||||
|
contextLimitLarge: 1000000
|
||||||
|
lowBalanceColorAlert: 500000
|
||||||
|
enabled: true
|
||||||
|
- id: gptoss-120b
|
||||||
|
displayName: GPT-OSS 120B
|
||||||
|
contextLimitSmall: 128000
|
||||||
|
contextLimitLarge: 128000
|
||||||
|
lowBalanceColorAlert: 500000
|
||||||
|
enabled: true
|
||||||
|
- id: qwen-235b
|
||||||
|
displayName: QWEN 235B
|
||||||
|
contextLimitSmall: 256000
|
||||||
|
contextLimitLarge: 256000
|
||||||
|
lowBalanceColorAlert: 500000
|
||||||
|
enabled: true
|
||||||
|
|||||||
@@ -43,10 +43,26 @@
|
|||||||
|
|
||||||
No Virtual Machines Found
|
No Virtual Machines Found
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- else %}
|
{%- elif baseDomainStatus == 'ImageDownloadStart' %}
|
||||||
|
#### INFO
|
||||||
|
|
||||||
|
Base domain image download started.
|
||||||
|
{%- elif baseDomainStatus == 'ImageDownloadFailed' %}
|
||||||
|
#### ERROR
|
||||||
|
|
||||||
|
Base domain image download failed. Please check the salt-master log for details and verify network connectivity.
|
||||||
|
{%- elif baseDomainStatus == 'SSHKeySetupFailed' %}
|
||||||
|
#### ERROR
|
||||||
|
|
||||||
|
SSH key setup failed. Please check the salt-master log for details.
|
||||||
|
{%- elif baseDomainStatus == 'SetupFailed' %}
|
||||||
#### WARNING
|
#### WARNING
|
||||||
|
|
||||||
Base domain has not been initialized.
|
Setup failed. Please check the salt-master log for details.
|
||||||
|
{%- elif baseDomainStatus == 'PreInit' %}
|
||||||
|
#### WARNING
|
||||||
|
|
||||||
|
Base domain has not been initialized. Waiting for hypervisor to highstate.
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ so-soc:
|
|||||||
- /opt/so/conf/strelka:/opt/sensoroni/yara:rw
|
- /opt/so/conf/strelka:/opt/sensoroni/yara:rw
|
||||||
- /opt/so/conf/sigma:/opt/sensoroni/sigma:rw
|
- /opt/so/conf/sigma:/opt/sensoroni/sigma:rw
|
||||||
- /opt/so/rules/elastalert/rules:/opt/sensoroni/elastalert:rw
|
- /opt/so/rules/elastalert/rules:/opt/sensoroni/elastalert:rw
|
||||||
- /opt/so/rules/nids/suri:/opt/sensoroni/nids:ro
|
- /opt/so/saltstack/local/salt/suricata/rules:/opt/sensoroni/suricata/rules:rw
|
||||||
|
- /opt/so/saltstack/local/salt/suricata/files:/opt/sensoroni/suricata/threshold:rw
|
||||||
- /opt/so/conf/soc/fingerprints:/opt/sensoroni/fingerprints:rw
|
- /opt/so/conf/soc/fingerprints:/opt/sensoroni/fingerprints:rw
|
||||||
- /nsm/soc/jobs:/opt/sensoroni/jobs:rw
|
- /nsm/soc/jobs:/opt/sensoroni/jobs:rw
|
||||||
- /nsm/soc/uploads:/nsm/soc/uploads:rw
|
- /nsm/soc/uploads:/nsm/soc/uploads:rw
|
||||||
|
|||||||
@@ -45,6 +45,61 @@ Finally, commit it:
|
|||||||
The next time the Strelka / YARA engine syncs, the new rule should be imported
|
The next time the Strelka / YARA engine syncs, the new rule should be imported
|
||||||
If there are errors, review the sync log to troubleshoot further.
|
If there are errors, review the sync log to troubleshoot further.
|
||||||
|
|
||||||
|
{% elif repo_type == 'suricata' %}
|
||||||
|
# Suricata Local Custom Rules Repository
|
||||||
|
|
||||||
|
This folder has already been initialized as a git repo
|
||||||
|
and your Security Onion grid is configured to import any Suricata rule files found here.
|
||||||
|
|
||||||
|
Just add your rule file and commit it.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
** Note: If this is your first time making changes to this repo, you may run into the following error:
|
||||||
|
|
||||||
|
fatal: detected dubious ownership in repository at '/nsm/rules/custom-local-repos/local-suricata'
|
||||||
|
To add an exception for this directory, call:
|
||||||
|
git config --global --add safe.directory /nsm/rules/custom-local-repos/local-suricata
|
||||||
|
|
||||||
|
This means that the user you are running commands as does not match the user that is used for this git repo (socore).
|
||||||
|
You will need to make sure your rule files are accessible to the socore user, so either su to socore
|
||||||
|
or add the exception and then chown the rule files later.
|
||||||
|
|
||||||
|
Also, you will be asked to set some configuration:
|
||||||
|
```
|
||||||
|
Author identity unknown
|
||||||
|
*** Please tell me who you are.
|
||||||
|
Run
|
||||||
|
git config --global user.email "you@example.com"
|
||||||
|
git config --global user.name "Your Name"
|
||||||
|
to set your account's default identity.
|
||||||
|
Omit --global to set the identity only in this repository.
|
||||||
|
```
|
||||||
|
|
||||||
|
Run these commands, ommitting the `--global`.
|
||||||
|
|
||||||
|
With that out of the way:
|
||||||
|
|
||||||
|
First, create the rule file with a .rules extension:
|
||||||
|
`vi my_custom_rules.rules`
|
||||||
|
|
||||||
|
Next, use git to stage the new rule to be committed:
|
||||||
|
`git add my_custom_rules.rules`
|
||||||
|
|
||||||
|
Finally, commit it:
|
||||||
|
`git commit -m "Initial commit of my_custom_rule.rules"`
|
||||||
|
|
||||||
|
The next time the Suricata engine syncs, the new rule/s should be imported
|
||||||
|
If there are errors, review the sync log to troubleshoot further.
|
||||||
|
|
||||||
|
{% elif repo_type == 'suricata-etpro' %}
|
||||||
|
# Suricata ETPRO - Airgap
|
||||||
|
|
||||||
|
This folder has been initialized for use with ETPRO during Airgap deployment.
|
||||||
|
|
||||||
|
Just add your ETPRO rule/s file to this folder and the Suricata engine will import them.
|
||||||
|
|
||||||
|
If there are errors, review the sync log to troubleshoot further.
|
||||||
{% elif repo_type == 'sigma' %}
|
{% elif repo_type == 'sigma' %}
|
||||||
# Sigma Local Custom Rules Repository
|
# Sigma Local Custom Rules Repository
|
||||||
|
|
||||||
|
|||||||
@@ -50,17 +50,86 @@
|
|||||||
{% do SOCMERGED.config.server.modules.elastalertengine.update({'enabledSigmaRules': SOCMERGED.config.server.modules.elastalertengine.enabledSigmaRules.default}) %}
|
{% do SOCMERGED.config.server.modules.elastalertengine.update({'enabledSigmaRules': SOCMERGED.config.server.modules.elastalertengine.enabledSigmaRules.default}) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# set elastalertengine.rulesRepos and strelkaengine.rulesRepos based on airgap or not #}
|
{# set elastalertengine.rulesRepos, strelkaengine.rulesRepos, and suricataengine.rulesetSources based on airgap or not #}
|
||||||
{% if GLOBALS.airgap %}
|
{% if GLOBALS.airgap %}
|
||||||
{% do SOCMERGED.config.server.modules.elastalertengine.update({'rulesRepos': SOCMERGED.config.server.modules.elastalertengine.rulesRepos.airgap}) %}
|
{% do SOCMERGED.config.server.modules.elastalertengine.update({'rulesRepos': SOCMERGED.config.server.modules.elastalertengine.rulesRepos.airgap}) %}
|
||||||
{% do SOCMERGED.config.server.modules.strelkaengine.update({'rulesRepos': SOCMERGED.config.server.modules.strelkaengine.rulesRepos.airgap}) %}
|
{% do SOCMERGED.config.server.modules.strelkaengine.update({'rulesRepos': SOCMERGED.config.server.modules.strelkaengine.rulesRepos.airgap}) %}
|
||||||
|
{#% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is mapping %#}
|
||||||
|
{% do SOCMERGED.config.server.modules.suricataengine.update({'rulesetSources': SOCMERGED.config.server.modules.suricataengine.rulesetSources.airgap}) %}
|
||||||
|
{#% endif %#}
|
||||||
{% do SOCMERGED.config.server.update({'airgapEnabled': true}) %}
|
{% do SOCMERGED.config.server.update({'airgapEnabled': true}) %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% do SOCMERGED.config.server.modules.elastalertengine.update({'rulesRepos': SOCMERGED.config.server.modules.elastalertengine.rulesRepos.default}) %}
|
{% do SOCMERGED.config.server.modules.elastalertengine.update({'rulesRepos': SOCMERGED.config.server.modules.elastalertengine.rulesRepos.default}) %}
|
||||||
{% do SOCMERGED.config.server.modules.strelkaengine.update({'rulesRepos': SOCMERGED.config.server.modules.strelkaengine.rulesRepos.default}) %}
|
{% do SOCMERGED.config.server.modules.strelkaengine.update({'rulesRepos': SOCMERGED.config.server.modules.strelkaengine.rulesRepos.default}) %}
|
||||||
|
{#% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is mapping %#}
|
||||||
|
{% do SOCMERGED.config.server.modules.suricataengine.update({'rulesetSources': SOCMERGED.config.server.modules.suricataengine.rulesetSources.default}) %}
|
||||||
|
{#% endif %#}
|
||||||
{% do SOCMERGED.config.server.update({'airgapEnabled': false}) %}
|
{% do SOCMERGED.config.server.update({'airgapEnabled': false}) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{# Define the Detections custom ruleset that should always be present #}
|
||||||
|
{% set CUSTOM_RULESET = {
|
||||||
|
'name': 'custom',
|
||||||
|
'description': 'User-created custom rules created via the Detections module in the SOC UI',
|
||||||
|
'sourceType': 'elasticsearch',
|
||||||
|
'sourcePath': 'so_detection.ruleset:__custom__',
|
||||||
|
'readOnly': false,
|
||||||
|
'deleteUnreferenced': false,
|
||||||
|
'license': 'Custom',
|
||||||
|
'enabled': true
|
||||||
|
} %}
|
||||||
|
|
||||||
|
{# Always append the custom ruleset to suricataengine.rulesetSources if not already present #}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine is defined and SOCMERGED.config.server.modules.suricataengine.rulesetSources is defined %}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is not mapping %}
|
||||||
|
{% set custom_names = SOCMERGED.config.server.modules.suricataengine.rulesetSources | selectattr('name', 'equalto', 'custom') | list %}
|
||||||
|
{% if custom_names | length == 0 %}
|
||||||
|
{% do SOCMERGED.config.server.modules.suricataengine.rulesetSources.append(CUSTOM_RULESET) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Enable SO_FILTERS and SO_EXTRACTIONS when Suricata is the metadata engine #}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine is defined and SOCMERGED.config.server.modules.suricataengine.rulesetSources is defined %}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is not mapping %}
|
||||||
|
{% for ruleset in SOCMERGED.config.server.modules.suricataengine.rulesetSources %}
|
||||||
|
{% if ruleset.name in ['SO_FILTERS', 'SO_EXTRACTIONS'] and GLOBALS.md_engine == 'SURICATA' %}
|
||||||
|
{% do ruleset.update({'enabled': true}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Transform Emerging-Threats ruleset based on license key #}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine is defined and SOCMERGED.config.server.modules.suricataengine.rulesetSources is defined %}
|
||||||
|
{% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is not mapping %}
|
||||||
|
{% for ruleset in SOCMERGED.config.server.modules.suricataengine.rulesetSources %}
|
||||||
|
{% if ruleset.name == 'Emerging-Threats' %}
|
||||||
|
{% if ruleset.licenseKey and ruleset.licenseKey != '' %}
|
||||||
|
{# License key is defined - transform to ETPRO #}
|
||||||
|
{# Engine Version is hardcoded in the URL - this does not change often: https://community.emergingthreats.net/t/supported-engines/71 #}
|
||||||
|
{% do ruleset.update({
|
||||||
|
'name': 'ETPRO',
|
||||||
|
'sourcePath': 'https://rules.emergingthreatspro.com/' ~ ruleset.licenseKey ~ '/suricata-7.0.3/etpro.rules.tar.gz',
|
||||||
|
'urlHash': 'https://rules.emergingthreatspro.com/' ~ ruleset.licenseKey ~ '/suricata-7.0.3/etpro.rules.tar.gz.md5',
|
||||||
|
'license': 'Commercial'
|
||||||
|
}) %}
|
||||||
|
{% else %}
|
||||||
|
{# No license key - explicitly set to ETOPEN #}
|
||||||
|
{% do ruleset.update({
|
||||||
|
'name': 'ETOPEN',
|
||||||
|
'sourcePath': 'https://rules.emergingthreats.net/open/suricata-7.0.3/emerging.rules.tar.gz',
|
||||||
|
'urlHash': 'https://rules.emergingthreats.net/open/suricata-7.0.3/emerging.rules.tar.gz.md5',
|
||||||
|
'license': 'BSD'
|
||||||
|
}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{# set playbookRepos based on airgap or not #}
|
{# set playbookRepos based on airgap or not #}
|
||||||
{% if GLOBALS.airgap %}
|
{% if GLOBALS.airgap %}
|
||||||
{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepos': SOCMERGED.config.server.modules.playbook.playbookRepos.airgap}) %}
|
{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepos': SOCMERGED.config.server.modules.playbook.playbookRepos.airgap}) %}
|
||||||
|
|||||||
@@ -424,6 +424,17 @@ soc:
|
|||||||
description: The maximum number of documents to request in a single Elasticsearch scroll request.
|
description: The maximum number of documents to request in a single Elasticsearch scroll request.
|
||||||
bulkIndexWorkerCount:
|
bulkIndexWorkerCount:
|
||||||
description: The number of worker threads to use when bulk indexing data into Elasticsearch. A value below 1 will default to the number of CPUs available.
|
description: The number of worker threads to use when bulk indexing data into Elasticsearch. A value below 1 will default to the number of CPUs available.
|
||||||
|
filedatastore:
|
||||||
|
jobDir:
|
||||||
|
description: The location where local job files are stored on the manager.
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
retryFailureIntervalMs:
|
||||||
|
description: The interval, in milliseconds, to wait before attempting to reprocess a failed job.
|
||||||
|
global: True
|
||||||
|
retryFailureMaxAttempts:
|
||||||
|
description: The max number of attempts to process a job, in the event the job fails to complete.
|
||||||
|
global: True
|
||||||
sostatus:
|
sostatus:
|
||||||
refreshIntervalMs:
|
refreshIntervalMs:
|
||||||
description: Duration (in milliseconds) between refreshes of the grid status. Shortening this duration may not have expected results, as the backend systems feeding this sostatus data will continue their updates as scheduled.
|
description: Duration (in milliseconds) between refreshes of the grid status. Shortening this duration may not have expected results, as the backend systems feeding this sostatus data will continue their updates as scheduled.
|
||||||
@@ -552,6 +563,52 @@ soc:
|
|||||||
advanced: True
|
advanced: True
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
helpLink: detections.html#rule-engine-status
|
helpLink: detections.html#rule-engine-status
|
||||||
|
rulesetSources:
|
||||||
|
default: &serulesetSources
|
||||||
|
description: "Ruleset sources for Suricata rules. Supports URL downloads and local directories. Refer to the linked documentation for details on how to configure this setting."
|
||||||
|
global: True
|
||||||
|
advanced: False
|
||||||
|
forcedType: "[]{}"
|
||||||
|
helpLink: suricata.html
|
||||||
|
syntax: json
|
||||||
|
uiElements:
|
||||||
|
- field: name
|
||||||
|
label: Ruleset Name (This will be the name of the ruleset in the UI)
|
||||||
|
required: True
|
||||||
|
readonly: True
|
||||||
|
- field: description
|
||||||
|
label: Description
|
||||||
|
- field: enabled
|
||||||
|
label: Enabled (If false, existing rules & overrides will be removed)
|
||||||
|
forcedType: bool
|
||||||
|
required: True
|
||||||
|
- field: licenseKey
|
||||||
|
label: License Key
|
||||||
|
required: False
|
||||||
|
- field: sourceType
|
||||||
|
label: Source Type
|
||||||
|
required: True
|
||||||
|
options:
|
||||||
|
- url
|
||||||
|
- directory
|
||||||
|
- field: sourcePath
|
||||||
|
label: Source Path (full url or directory path)
|
||||||
|
required: True
|
||||||
|
- field: excludeFiles
|
||||||
|
label: Exclude Files (list of file names to exclude, separated by commas)
|
||||||
|
required: False
|
||||||
|
- field: license
|
||||||
|
label: Ruleset License
|
||||||
|
required: True
|
||||||
|
- field: readOnly
|
||||||
|
label: Read Only (Prevents changes to the rule itself - can still be enabled/disabled/tuned)
|
||||||
|
forcedType: bool
|
||||||
|
required: False
|
||||||
|
- field: deleteUnreferenced
|
||||||
|
label: Delete Unreferenced (Deletes rules that are no longer referenced by ruleset source)
|
||||||
|
forcedType: bool
|
||||||
|
required: False
|
||||||
|
airgap: *serulesetSources
|
||||||
navigator:
|
navigator:
|
||||||
intervalMinutes:
|
intervalMinutes:
|
||||||
description: How often to generate the Navigator Layers. (minutes)
|
description: How often to generate the Navigator Layers. (minutes)
|
||||||
@@ -606,14 +663,9 @@ soc:
|
|||||||
investigationPrompt:
|
investigationPrompt:
|
||||||
description: Prompt given to Onion AI when beginning an investigation.
|
description: Prompt given to Onion AI when beginning an investigation.
|
||||||
global: True
|
global: True
|
||||||
contextLimitSmall:
|
compressContextPrompt:
|
||||||
description: Smaller context limit for Onion AI.
|
description: Prompt given to Onion AI when summarizing a conversation in order to compress context.
|
||||||
global: True
|
global: True
|
||||||
advanced: True
|
|
||||||
contextLimitLarge:
|
|
||||||
description: Larger context limit for Onion AI.
|
|
||||||
global: True
|
|
||||||
advanced: True
|
|
||||||
thresholdColorRatioLow:
|
thresholdColorRatioLow:
|
||||||
description: Lower visual context color change threshold.
|
description: Lower visual context color change threshold.
|
||||||
global: True
|
global: True
|
||||||
@@ -630,6 +682,35 @@ soc:
|
|||||||
description: Onion AI credit amount at which balance turns red.
|
description: Onion AI credit amount at which balance turns red.
|
||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
|
availableModels:
|
||||||
|
description: List of AI models available for use in SOC as well as model specific warning thresholds.
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
forcedType: "[]{}"
|
||||||
|
helpLink: assistant.html
|
||||||
|
syntax: json
|
||||||
|
uiElements:
|
||||||
|
- field: id
|
||||||
|
label: Model ID
|
||||||
|
required: True
|
||||||
|
- field: displayName
|
||||||
|
label: Display Name
|
||||||
|
required: True
|
||||||
|
- field: contextLimitSmall
|
||||||
|
label: Context Limit (Small)
|
||||||
|
forcedType: int
|
||||||
|
required: True
|
||||||
|
- field: contextLimitLarge
|
||||||
|
label: Context Limit (Large)
|
||||||
|
forcedType: int
|
||||||
|
required: True
|
||||||
|
- field: lowBalanceColorAlert
|
||||||
|
label: Low Balance Color Alert
|
||||||
|
forcedType: int
|
||||||
|
required: True
|
||||||
|
- field: enabled
|
||||||
|
label: Enabled
|
||||||
|
forcedType: bool
|
||||||
apiTimeoutMs:
|
apiTimeoutMs:
|
||||||
description: Duration (in milliseconds) to wait for a response from the SOC server API before giving up and showing an error on the SOC UI.
|
description: Duration (in milliseconds) to wait for a response from the SOC server API before giving up and showing an error on the SOC UI.
|
||||||
global: True
|
global: True
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ include:
|
|||||||
|
|
||||||
strelka_filestream:
|
strelka_filestream:
|
||||||
docker_container.running:
|
docker_container.running:
|
||||||
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-filestream:{{ GLOBALS.so_version }}
|
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }}
|
||||||
- binds:
|
- binds:
|
||||||
- /opt/so/conf/strelka/filestream/:/etc/strelka/:ro
|
- /opt/so/conf/strelka/filestream/:/etc/strelka/:ro
|
||||||
- /nsm/strelka:/nsm/strelka
|
- /nsm/strelka:/nsm/strelka
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ include:
|
|||||||
|
|
||||||
strelka_frontend:
|
strelka_frontend:
|
||||||
docker_container.running:
|
docker_container.running:
|
||||||
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-frontend:{{ GLOBALS.so_version }}
|
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }}
|
||||||
- binds:
|
- binds:
|
||||||
- /opt/so/conf/strelka/frontend/:/etc/strelka/:ro
|
- /opt/so/conf/strelka/frontend/:/etc/strelka/:ro
|
||||||
- /nsm/strelka/log/:/var/log/strelka/:rw
|
- /nsm/strelka/log/:/var/log/strelka/:rw
|
||||||
|
|||||||
@@ -7,9 +7,49 @@
|
|||||||
{% if sls.split('.')[0] in allowed_states %}
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
|
||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'bpf/suricata.map.jinja' import SURICATABPF %}
|
|
||||||
{% from 'suricata/map.jinja' import SURICATAMERGED %}
|
{% from 'suricata/map.jinja' import SURICATAMERGED %}
|
||||||
{% set BPF_STATUS = 0 %}
|
{% from 'bpf/suricata.map.jinja' import SURICATABPF, SURICATA_BPF_STATUS, SURICATA_BPF_CALC %}
|
||||||
|
|
||||||
|
{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %}
|
||||||
|
{% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS, PCAP_BPF_CALC %}
|
||||||
|
# BPF compilation and configuration
|
||||||
|
{% if PCAPBPF and not PCAP_BPF_STATUS %}
|
||||||
|
suriPCAPbpfcompilationfailure:
|
||||||
|
test.configurable_test_state:
|
||||||
|
- changes: False
|
||||||
|
- result: False
|
||||||
|
- comment: "BPF Syntax Error - Discarding Specified BPF. Error: {{ PCAP_BPF_CALC['stderr'] }}"
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
suridir:
|
||||||
|
file.directory:
|
||||||
|
- name: /opt/so/conf/suricata
|
||||||
|
- user: 940
|
||||||
|
- group: 939
|
||||||
|
- mode: 775
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
# BPF applied to all of Suricata - alerts/metadata/pcap
|
||||||
|
suribpf:
|
||||||
|
file.managed:
|
||||||
|
- name: /opt/so/conf/suricata/bpf
|
||||||
|
- user: 940
|
||||||
|
- group: 940
|
||||||
|
{% if SURICATA_BPF_STATUS %}
|
||||||
|
- contents: {{ SURICATABPF }}
|
||||||
|
{% else %}
|
||||||
|
- contents:
|
||||||
|
- ""
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if SURICATABPF and not SURICATA_BPF_STATUS %}
|
||||||
|
suribpfcompilationfailure:
|
||||||
|
test.configurable_test_state:
|
||||||
|
- changes: False
|
||||||
|
- result: False
|
||||||
|
- comment: "BPF Syntax Error - Discarding Specified BPF. Error: {{ SURICATA_BPF_CALC['stderr'] }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Add Suricata Group
|
# Add Suricata Group
|
||||||
suricatagroup:
|
suricatagroup:
|
||||||
@@ -49,17 +89,12 @@ suricata_sbin_jinja:
|
|||||||
- file_mode: 755
|
- file_mode: 755
|
||||||
- template: jinja
|
- template: jinja
|
||||||
|
|
||||||
suridir:
|
|
||||||
file.directory:
|
|
||||||
- name: /opt/so/conf/suricata
|
|
||||||
- user: 940
|
|
||||||
- group: 940
|
|
||||||
|
|
||||||
suriruledir:
|
suriruledir:
|
||||||
file.directory:
|
file.directory:
|
||||||
- name: /opt/so/conf/suricata/rules
|
- name: /opt/so/rules/suricata
|
||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 939
|
||||||
|
- mode: 775
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
surilogdir:
|
surilogdir:
|
||||||
@@ -84,14 +119,12 @@ suridatadir:
|
|||||||
- mode: 770
|
- mode: 770
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|
||||||
# salt:// would resolve to /opt/so/rules/nids because of the defined file_roots and
|
|
||||||
# not existing under /opt/so/saltstack/local/salt or /opt/so/saltstack/default/salt
|
|
||||||
surirulesync:
|
surirulesync:
|
||||||
file.recurse:
|
file.recurse:
|
||||||
- name: /opt/so/conf/suricata/rules/
|
- name: /opt/so/rules/suricata/
|
||||||
- source: salt://suri/
|
- source: salt://suricata/rules/
|
||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 939
|
||||||
- show_changes: False
|
- show_changes: False
|
||||||
|
|
||||||
surilogscript:
|
surilogscript:
|
||||||
@@ -124,10 +157,9 @@ suriconfig:
|
|||||||
surithresholding:
|
surithresholding:
|
||||||
file.managed:
|
file.managed:
|
||||||
- name: /opt/so/conf/suricata/threshold.conf
|
- name: /opt/so/conf/suricata/threshold.conf
|
||||||
- source: salt://suricata/files/threshold.conf.jinja
|
- source: salt://suricata/files/threshold.conf
|
||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 940
|
||||||
- template: jinja
|
|
||||||
|
|
||||||
suriclassifications:
|
suriclassifications:
|
||||||
file.managed:
|
file.managed:
|
||||||
@@ -136,32 +168,6 @@ suriclassifications:
|
|||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 940
|
||||||
|
|
||||||
# BPF compilation and configuration
|
|
||||||
{% if SURICATABPF %}
|
|
||||||
{% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %}
|
|
||||||
{% if BPF_CALC['stderr'] == "" %}
|
|
||||||
{% set BPF_STATUS = 1 %}
|
|
||||||
{% else %}
|
|
||||||
suribpfcompilationfailure:
|
|
||||||
test.configurable_test_state:
|
|
||||||
- changes: False
|
|
||||||
- result: False
|
|
||||||
- comment: "BPF Syntax Error - Discarding Specified BPF"
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
suribpf:
|
|
||||||
file.managed:
|
|
||||||
- name: /opt/so/conf/suricata/bpf
|
|
||||||
- user: 940
|
|
||||||
- group: 940
|
|
||||||
{% if BPF_STATUS %}
|
|
||||||
- contents: {{ SURICATABPF }}
|
|
||||||
{% else %}
|
|
||||||
- contents:
|
|
||||||
- ""
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
so-suricata-eve-clean:
|
so-suricata-eve-clean:
|
||||||
file.managed:
|
file.managed:
|
||||||
- name: /usr/sbin/so-suricata-eve-clean
|
- name: /usr/sbin/so-suricata-eve-clean
|
||||||
@@ -171,6 +177,14 @@ so-suricata-eve-clean:
|
|||||||
- template: jinja
|
- template: jinja
|
||||||
- source: salt://suricata/cron/so-suricata-eve-clean
|
- source: salt://suricata/cron/so-suricata-eve-clean
|
||||||
|
|
||||||
|
so-suricata-rulestats:
|
||||||
|
file.managed:
|
||||||
|
- name: /usr/sbin/so-suricata-rulestats
|
||||||
|
- user: root
|
||||||
|
- group: root
|
||||||
|
- mode: 755
|
||||||
|
- source: salt://suricata/cron/so-suricata-rulestats
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
30
salt/suricata/cron/so-suricata-rulestats
Normal file
30
salt/suricata/cron/so-suricata-rulestats
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
# Query Suricata for ruleset stats and reload time, write to JSON file for Telegraf to consume
|
||||||
|
|
||||||
|
OUTFILE="/opt/so/log/suricata/rulestats.json"
|
||||||
|
SURICATASC="docker exec so-suricata /opt/suricata/bin/suricatasc"
|
||||||
|
SOCKET="/var/run/suricata/suricata-command.socket"
|
||||||
|
|
||||||
|
query() {
|
||||||
|
timeout 10 $SURICATASC -c "$1" "$SOCKET" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
STATS=$(query "ruleset-stats")
|
||||||
|
RELOAD=$(query "ruleset-reload-time")
|
||||||
|
|
||||||
|
if echo "$STATS" | jq -e '.return == "OK"' > /dev/null 2>&1; then
|
||||||
|
LOADED=$(echo "$STATS" | jq -r '.message[0].rules_loaded')
|
||||||
|
FAILED=$(echo "$STATS" | jq -r '.message[0].rules_failed')
|
||||||
|
LAST_RELOAD=$(echo "$RELOAD" | jq -r '.message[0].last_reload')
|
||||||
|
|
||||||
|
jq -n --argjson loaded "$LOADED" --argjson failed "$FAILED" --arg reload "$LAST_RELOAD" \
|
||||||
|
'{rules_loaded: $loaded, rules_failed: $failed, last_reload: $reload, return: "OK"}' > "$OUTFILE"
|
||||||
|
else
|
||||||
|
echo '{"return":"FAIL"}' > "$OUTFILE"
|
||||||
|
fi
|
||||||
@@ -34,7 +34,7 @@ suricata:
|
|||||||
threads: 1
|
threads: 1
|
||||||
tpacket-v3: "yes"
|
tpacket-v3: "yes"
|
||||||
ring-size: 5000
|
ring-size: 5000
|
||||||
block-size: 32768
|
block-size: 69632
|
||||||
block-timeout: 10
|
block-timeout: 10
|
||||||
use-emergency-flush: "yes"
|
use-emergency-flush: "yes"
|
||||||
buffer-size: 32768
|
buffer-size: 32768
|
||||||
@@ -97,6 +97,11 @@ suricata:
|
|||||||
- 4789
|
- 4789
|
||||||
TEREDO_PORTS:
|
TEREDO_PORTS:
|
||||||
- 3544
|
- 3544
|
||||||
|
SIP_PORTS:
|
||||||
|
- 5060
|
||||||
|
- 5061
|
||||||
|
GENEVE_PORTS:
|
||||||
|
- 6081
|
||||||
default-log-dir: /var/log/suricata/
|
default-log-dir: /var/log/suricata/
|
||||||
stats:
|
stats:
|
||||||
enabled: "yes"
|
enabled: "yes"
|
||||||
@@ -134,14 +139,6 @@ suricata:
|
|||||||
header: X-Forwarded-For
|
header: X-Forwarded-For
|
||||||
unified2-alert:
|
unified2-alert:
|
||||||
enabled: "no"
|
enabled: "no"
|
||||||
http-log:
|
|
||||||
enabled: "no"
|
|
||||||
filename: http.log
|
|
||||||
append: "yes"
|
|
||||||
tls-log:
|
|
||||||
enabled: "no"
|
|
||||||
filename: tls.log
|
|
||||||
append: "yes"
|
|
||||||
tls-store:
|
tls-store:
|
||||||
enabled: "no"
|
enabled: "no"
|
||||||
pcap-log:
|
pcap-log:
|
||||||
@@ -157,9 +154,6 @@ suricata:
|
|||||||
totals: "yes"
|
totals: "yes"
|
||||||
threads: "no"
|
threads: "no"
|
||||||
null-values: "yes"
|
null-values: "yes"
|
||||||
syslog:
|
|
||||||
enabled: "no"
|
|
||||||
facility: local5
|
|
||||||
drop:
|
drop:
|
||||||
enabled: "no"
|
enabled: "no"
|
||||||
file-store:
|
file-store:
|
||||||
@@ -206,6 +200,9 @@ suricata:
|
|||||||
enabled: "yes"
|
enabled: "yes"
|
||||||
detection-ports:
|
detection-ports:
|
||||||
dp: 443
|
dp: 443
|
||||||
|
ja3-fingerprints: auto
|
||||||
|
ja4-fingerprints: auto
|
||||||
|
encryption-handling: track-only
|
||||||
dcerpc:
|
dcerpc:
|
||||||
enabled: "yes"
|
enabled: "yes"
|
||||||
ftp:
|
ftp:
|
||||||
@@ -255,19 +252,21 @@ suricata:
|
|||||||
libhtp:
|
libhtp:
|
||||||
default-config:
|
default-config:
|
||||||
personality: IDS
|
personality: IDS
|
||||||
request-body-limit: 100kb
|
request-body-limit: 100 KiB
|
||||||
response-body-limit: 100kb
|
response-body-limit: 100 KiB
|
||||||
request-body-minimal-inspect-size: 32kb
|
request-body-minimal-inspect-size: 32 KiB
|
||||||
request-body-inspect-window: 4kb
|
request-body-inspect-window: 4 KiB
|
||||||
response-body-minimal-inspect-size: 40kb
|
response-body-minimal-inspect-size: 40 KiB
|
||||||
response-body-inspect-window: 16kb
|
response-body-inspect-window: 16 KiB
|
||||||
response-body-decompress-layer-limit: 2
|
response-body-decompress-layer-limit: 2
|
||||||
http-body-inline: auto
|
http-body-inline: auto
|
||||||
swf-decompression:
|
swf-decompression:
|
||||||
enabled: "yes"
|
enabled: "no"
|
||||||
type: both
|
type: both
|
||||||
compress-depth: 0
|
compress-depth: 100 KiB
|
||||||
decompress-depth: 0
|
decompress-depth: 100 KiB
|
||||||
|
randomize-inspection-sizes: "yes"
|
||||||
|
randomize-inspection-range: 10
|
||||||
double-decode-path: "no"
|
double-decode-path: "no"
|
||||||
double-decode-query: "no"
|
double-decode-query: "no"
|
||||||
server-config:
|
server-config:
|
||||||
@@ -401,8 +400,12 @@ suricata:
|
|||||||
vxlan:
|
vxlan:
|
||||||
enabled: true
|
enabled: true
|
||||||
ports: $VXLAN_PORTS
|
ports: $VXLAN_PORTS
|
||||||
erspan:
|
geneve:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
ports: $GENEVE_PORTS
|
||||||
|
max-layers: 16
|
||||||
|
recursion-level:
|
||||||
|
use-for-tracking: true
|
||||||
detect:
|
detect:
|
||||||
profile: medium
|
profile: medium
|
||||||
custom-values:
|
custom-values:
|
||||||
@@ -422,7 +425,12 @@ suricata:
|
|||||||
spm-algo: auto
|
spm-algo: auto
|
||||||
luajit:
|
luajit:
|
||||||
states: 128
|
states: 128
|
||||||
|
security:
|
||||||
|
lua:
|
||||||
|
allow-rules: false
|
||||||
|
max-bytes: 500000
|
||||||
|
max-instructions: 500000
|
||||||
|
allow-restricted-functions: false
|
||||||
profiling:
|
profiling:
|
||||||
rules:
|
rules:
|
||||||
enabled: "yes"
|
enabled: "yes"
|
||||||
@@ -459,7 +467,7 @@ suricata:
|
|||||||
append: "yes"
|
append: "yes"
|
||||||
default-rule-path: /etc/suricata/rules
|
default-rule-path: /etc/suricata/rules
|
||||||
rule-files:
|
rule-files:
|
||||||
- all.rules
|
- all-rulesets.rules
|
||||||
classification-file: /etc/suricata/classification.config
|
classification-file: /etc/suricata/classification.config
|
||||||
reference-config-file: /etc/suricata/reference.config
|
reference-config-file: /etc/suricata/reference.config
|
||||||
threshold-file: /etc/suricata/threshold.conf
|
threshold-file: /etc/suricata/threshold.conf
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ clean_suricata_eve_files:
|
|||||||
cron.absent:
|
cron.absent:
|
||||||
- identifier: clean_suricata_eve_files
|
- identifier: clean_suricata_eve_files
|
||||||
|
|
||||||
|
# Remove rulestats cron
|
||||||
|
rulestats:
|
||||||
|
cron.absent:
|
||||||
|
- identifier: suricata_rulestats
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ so-suricata:
|
|||||||
- /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro
|
- /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro
|
||||||
- /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro
|
- /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro
|
||||||
- /opt/so/conf/suricata/classification.config:/etc/suricata/classification.config:ro
|
- /opt/so/conf/suricata/classification.config:/etc/suricata/classification.config:ro
|
||||||
- /opt/so/conf/suricata/rules:/etc/suricata/rules:ro
|
- /opt/so/rules/suricata:/etc/suricata/rules:ro
|
||||||
- /opt/so/log/suricata/:/var/log/suricata/:rw
|
- /opt/so/log/suricata/:/var/log/suricata/:rw
|
||||||
- /nsm/suricata/:/nsm/:rw
|
- /nsm/suricata/:/nsm/:rw
|
||||||
- /nsm/suricata/extracted:/var/log/suricata//filestore:rw
|
- /nsm/suricata/extracted:/var/log/suricata//filestore:rw
|
||||||
@@ -90,6 +90,18 @@ clean_suricata_eve_files:
|
|||||||
- month: '*'
|
- month: '*'
|
||||||
- dayweek: '*'
|
- dayweek: '*'
|
||||||
|
|
||||||
|
# Add rulestats cron - runs every minute to query Suricata for rule load status
|
||||||
|
suricata_rulestats:
|
||||||
|
cron.present:
|
||||||
|
- name: /usr/sbin/so-suricata-rulestats > /dev/null 2>&1
|
||||||
|
- identifier: suricata_rulestats
|
||||||
|
- user: root
|
||||||
|
- minute: '*'
|
||||||
|
- hour: '*'
|
||||||
|
- daymonth: '*'
|
||||||
|
- month: '*'
|
||||||
|
- dayweek: '*'
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ alert smb any any -> any any (msg:"FILE ZIP detected"; filemagic:"Zip"; filestor
|
|||||||
alert http any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100016; rev:1;)
|
alert http any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100016; rev:1;)
|
||||||
alert smtp any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100017; rev:1;)
|
alert smtp any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100017; rev:1;)
|
||||||
alert nfs any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100018; rev:1;)
|
alert nfs any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100018; rev:1;)
|
||||||
alert smb any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100019; rev:1;)
|
alert smb any any -> any any (msg:"FILE WORDDOC detected"; filemagic:"Composite Document File V2 Document"; filestore; noalert; sid:1100019; rev:1;)
|
||||||
@@ -9,3 +9,4 @@
|
|||||||
#config tls any any -> any any (tls.fingerprint; content:"4f:a4:5e:58:7e:d9:db:20:09:d7:b6:c7:ff:58:c4:7b:dc:3f:55:b4"; config: logging disable, type tx, scope tx; sid:1200003;)
|
#config tls any any -> any any (tls.fingerprint; content:"4f:a4:5e:58:7e:d9:db:20:09:d7:b6:c7:ff:58:c4:7b:dc:3f:55:b4"; config: logging disable, type tx, scope tx; sid:1200003;)
|
||||||
# Example of filtering out a md5 of a file from being in the files log.
|
# Example of filtering out a md5 of a file from being in the files log.
|
||||||
#config fileinfo any any -> any any (fileinfo.filemd5; content:"7a125dc69c82d5caf94d3913eecde4b5"; config: logging disable, type tx, scope tx; sid:1200004;)
|
#config fileinfo any any -> any any (fileinfo.filemd5; content:"7a125dc69c82d5caf94d3913eecde4b5"; config: logging disable, type tx, scope tx; sid:1200004;)
|
||||||
|
|
||||||
2
salt/suricata/files/threshold.conf
Normal file
2
salt/suricata/files/threshold.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Threshold configuration generated by Security Onion
|
||||||
|
# This file is automatically generated - do not edit manually
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{% import_yaml 'suricata/thresholding/sids.yaml' as THRESHOLDING %}
|
|
||||||
{% if THRESHOLDING -%}
|
|
||||||
|
|
||||||
{% for EACH_SID in THRESHOLDING -%}
|
|
||||||
{% for ACTIONS_LIST in THRESHOLDING[EACH_SID] -%}
|
|
||||||
{% for EACH_ACTION in ACTIONS_LIST -%}
|
|
||||||
|
|
||||||
{%- if EACH_ACTION == 'threshold' %}
|
|
||||||
{{ EACH_ACTION }} gen_id {{ ACTIONS_LIST[EACH_ACTION].gen_id }}, sig_id {{ EACH_SID }}, type {{ ACTIONS_LIST[EACH_ACTION].type }}, track {{ ACTIONS_LIST[EACH_ACTION].track }}, count {{ ACTIONS_LIST[EACH_ACTION].count }}, seconds {{ ACTIONS_LIST[EACH_ACTION].seconds }}
|
|
||||||
|
|
||||||
{%- elif EACH_ACTION == 'rate_filter' %}
|
|
||||||
{%- if ACTIONS_LIST[EACH_ACTION].new_action not in ['drop','reject'] %}
|
|
||||||
{{ EACH_ACTION }} gen_id {{ ACTIONS_LIST[EACH_ACTION].gen_id }}, sig_id {{ EACH_SID }}, track {{ ACTIONS_LIST[EACH_ACTION].track }}, count {{ ACTIONS_LIST[EACH_ACTION].count }}, seconds {{ ACTIONS_LIST[EACH_ACTION].seconds }}, new_action {{ ACTIONS_LIST[EACH_ACTION].new_action }}, timeout {{ ACTIONS_LIST[EACH_ACTION].timeout }}
|
|
||||||
{%- else %}
|
|
||||||
##### Security Onion does not support drop or reject actions for rate_filter
|
|
||||||
##### {{ EACH_ACTION }} gen_id {{ ACTIONS_LIST[EACH_ACTION].gen_id }}, sig_id {{ EACH_SID }}, track {{ ACTIONS_LIST[EACH_ACTION].track }}, count {{ ACTIONS_LIST[EACH_ACTION].count }}, seconds {{ ACTIONS_LIST[EACH_ACTION].seconds }}, new_action {{ ACTIONS_LIST[EACH_ACTION].new_action }}, timeout {{ ACTIONS_LIST[EACH_ACTION].timeout }}
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{%- elif EACH_ACTION == 'suppress' %}
|
|
||||||
{%- if ACTIONS_LIST[EACH_ACTION].track is defined %}
|
|
||||||
{{ EACH_ACTION }} gen_id {{ ACTIONS_LIST[EACH_ACTION].gen_id }}, sig_id {{ EACH_SID }}, track {{ ACTIONS_LIST[EACH_ACTION].track }}, ip {{ ACTIONS_LIST[EACH_ACTION].ip }}
|
|
||||||
{%- else %}
|
|
||||||
{{ EACH_ACTION }} gen_id {{ ACTIONS_LIST[EACH_ACTION].gen_id }}, sig_id {{ EACH_SID }}
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endfor %}
|
|
||||||
|
|
||||||
{%- else %}
|
|
||||||
##### Navigate to suricata > thresholding > SIDS in SOC to define thresholding
|
|
||||||
|
|
||||||
{%- endif %}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
|
||||||
{% if sls in allowed_states %}
|
|
||||||
|
|
||||||
surilocaldir:
|
|
||||||
file.directory:
|
|
||||||
- name: /opt/so/saltstack/local/salt/suricata
|
|
||||||
- user: socore
|
|
||||||
- group: socore
|
|
||||||
- makedirs: True
|
|
||||||
|
|
||||||
ruleslink:
|
|
||||||
file.symlink:
|
|
||||||
- name: /opt/so/saltstack/local/salt/suricata/rules
|
|
||||||
- user: socore
|
|
||||||
- group: socore
|
|
||||||
- target: /opt/so/rules/nids/suri
|
|
||||||
|
|
||||||
refresh_salt_master_fileserver_suricata_ruleslink:
|
|
||||||
salt.runner:
|
|
||||||
- name: fileserver.update
|
|
||||||
- onchanges:
|
|
||||||
- file: ruleslink
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
|
||||||
test.fail_without_changes:
|
|
||||||
- name: {{sls}}_state_not_allowed
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -10,6 +10,12 @@
|
|||||||
|
|
||||||
{# before we change outputs back to list, enable pcap-log if suricata is the pcapengine #}
|
{# before we change outputs back to list, enable pcap-log if suricata is the pcapengine #}
|
||||||
{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %}
|
{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %}
|
||||||
|
|
||||||
|
{% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS %}
|
||||||
|
{% if PCAPBPF and PCAP_BPF_STATUS %}
|
||||||
|
{% do SURICATAMERGED.config.outputs['pcap-log'].update({'bpf-filter': PCAPBPF|join(" ")}) %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% do SURICATAMERGED.config.outputs['pcap-log'].update({'enabled': 'yes'}) %}
|
{% do SURICATAMERGED.config.outputs['pcap-log'].update({'enabled': 'yes'}) %}
|
||||||
{# move the items in suricata.pcap into suricata.config.outputs.pcap-log. these items were placed under suricata.config for ease of access in SOC #}
|
{# move the items in suricata.pcap into suricata.config.outputs.pcap-log. these items were placed under suricata.config for ease of access in SOC #}
|
||||||
{% do SURICATAMERGED.config.outputs['pcap-log'].update({'compression': SURICATAMERGED.pcap.compression}) %}
|
{% do SURICATAMERGED.config.outputs['pcap-log'].update({'compression': SURICATAMERGED.pcap.compression}) %}
|
||||||
|
|||||||
0
salt/suricata/rules/PLACEHOLDER
Normal file
0
salt/suricata/rules/PLACEHOLDER
Normal file
@@ -190,6 +190,8 @@ suricata:
|
|||||||
FTP_PORTS: *suriportgroup
|
FTP_PORTS: *suriportgroup
|
||||||
VXLAN_PORTS: *suriportgroup
|
VXLAN_PORTS: *suriportgroup
|
||||||
TEREDO_PORTS: *suriportgroup
|
TEREDO_PORTS: *suriportgroup
|
||||||
|
SIP_PORTS: *suriportgroup
|
||||||
|
GENEVE_PORTS: *suriportgroup
|
||||||
outputs:
|
outputs:
|
||||||
eve-log:
|
eve-log:
|
||||||
types:
|
types:
|
||||||
@@ -209,7 +211,7 @@ suricata:
|
|||||||
helpLink: suricata.html
|
helpLink: suricata.html
|
||||||
pcap-log:
|
pcap-log:
|
||||||
enabled:
|
enabled:
|
||||||
description: This value is ignored by SO. pcapengine in globals takes precidence.
|
description: This value is ignored by SO. pcapengine in globals takes precedence.
|
||||||
readonly: True
|
readonly: True
|
||||||
helpLink: suricata.html
|
helpLink: suricata.html
|
||||||
advanced: True
|
advanced: True
|
||||||
@@ -297,3 +299,10 @@ suricata:
|
|||||||
ports:
|
ports:
|
||||||
description: Ports to listen for. This should be a variable.
|
description: Ports to listen for. This should be a variable.
|
||||||
helpLink: suricata.html
|
helpLink: suricata.html
|
||||||
|
geneve:
|
||||||
|
enabled:
|
||||||
|
description: Enable VXLAN capabilities.
|
||||||
|
helpLink: suricata.html
|
||||||
|
ports:
|
||||||
|
description: Ports to listen for. This should be a variable.
|
||||||
|
helpLink: suricata.html
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ suricata:
|
|||||||
#custom: [Accept-Encoding, Accept-Language, Authorization]
|
#custom: [Accept-Encoding, Accept-Language, Authorization]
|
||||||
# dump-all-headers: none
|
# dump-all-headers: none
|
||||||
- dns:
|
- dns:
|
||||||
version: 2
|
version: 3
|
||||||
enabled: "yes"
|
enabled: "yes"
|
||||||
#requests: "no"
|
#requests: "no"
|
||||||
#responses: "no"
|
#responses: "no"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user