mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-07-27 19:26:42 +02:00
Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e141a1ad7 | ||
|
|
4de8f0208f | ||
|
|
4aabf7d638 | ||
|
|
812310088e | ||
|
|
4e17390cfa | ||
|
|
57d629683d | ||
|
|
3666b5b0de | ||
|
|
7f64f143d7 | ||
|
|
162c66a705 | ||
|
|
14d11cc180 | ||
|
|
112fcf7804 | ||
|
|
120b426a79 | ||
|
|
72fd754a92 | ||
|
|
d5fddafa6a | ||
|
|
0c83d4e1fe | ||
|
|
baca444a7e | ||
|
|
4f5af93b38 | ||
|
|
b109ca4e9b | ||
|
|
e5969a12aa | ||
|
|
4d97b562eb | ||
|
|
f2d81cea3f | ||
|
|
6bd3c414bb | ||
|
|
16f958dac0 | ||
|
|
a57ff5f89e | ||
|
|
e2513daddc | ||
|
|
01a873b2d9 | ||
|
|
19957d9530 | ||
|
|
4871098278 | ||
|
|
7b32c73da8 | ||
|
|
334978ad92 | ||
|
|
a21186ccce | ||
|
|
f77fad8087 | ||
|
|
963e475d1a | ||
|
|
ac46636196 | ||
|
|
f3d8bae13d | ||
|
|
894d323323 | ||
|
|
26eb8c3c18 | ||
|
|
4e1935f8a0 | ||
|
|
c4c1464b2a | ||
|
|
89f4950521 | ||
|
|
387781c629 | ||
|
|
011749ad09 | ||
|
|
ad78e84ccd |
@@ -133,6 +133,7 @@ if [[ $EXCLUDE_STARTUP_ERRORS == 'Y' ]]; then
|
|||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Cancelling deferred write event maybeFenceReplicas because the event queue is now closed" # Kafka controller log during shutdown/restart
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Cancelling deferred write event maybeFenceReplicas because the event queue is now closed" # Kafka controller log during shutdown/restart
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Redis may have been restarted" # Redis likely restarted by salt
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Redis may have been restarted" # Redis likely restarted by salt
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|file already closed" # Go logging race condition during container restart
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|file already closed" # Go logging race condition during container restart
|
||||||
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|relation \"audit_settings\" does not exist" # salt checking for changes before SOC starts
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
|
if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
|
||||||
@@ -230,7 +231,7 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
|
|||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|from NIC checksum offloading" # zeek reporter.log
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|from NIC checksum offloading" # zeek reporter.log
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|marked for removal" # docker container getting recycled
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|marked for removal" # docker container getting recycled
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tcp 127.0.0.1:6791: bind: address already in use" # so-elastic-fleet agent restarting. Seen starting w/ 8.18.8 https://github.com/elastic/kibana/issues/201459
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tcp 127.0.0.1:6791: bind: address already in use" # so-elastic-fleet agent restarting. Seen starting w/ 8.18.8 https://github.com/elastic/kibana/issues/201459
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|TransformTask\] \[logs-(tychon|aws_billing|microsoft_defender_endpoint|armis|o365_metrics|microsoft_sentinel|snyk|cyera|island_browser).*user so_kibana lacks the required permissions \[(logs|metrics)-\1" # Known issue with integrations starting transform jobs that are explicitly not allowed to start as a system user. This error should not be seen on fresh ES 9.3.3 installs or after SO 3.1.0 with soups addition of check_transform_health_and_reauthorize()
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|TransformTask\] \[logs-.*user so_kibana lacks the required permissions" # Known issue with integrations starting transform jobs that are explicitly not allowed to start as a system user
|
||||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|manifest unknown" # appears in so-dockerregistry log for so-tcpreplay following docker upgrade to 29.2.1-1
|
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|manifest unknown" # appears in so-dockerregistry log for so-tcpreplay following docker upgrade to 29.2.1-1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ case $1 in
|
|||||||
"elastic-fleet"|"elasticfleet")
|
"elastic-fleet"|"elasticfleet")
|
||||||
docker_check_running "elastic-fleet" "--stop"
|
docker_check_running "elastic-fleet" "--stop"
|
||||||
docker rm "so-elastic-fleet" 2> /dev/null
|
docker rm "so-elastic-fleet" 2> /dev/null
|
||||||
# Removing the elastic fleet state directory, so that the next startup re-enrolls with a fresh policy
|
|
||||||
rm -rf /opt/so/conf/elastic-fleet/state
|
|
||||||
|
|
||||||
salt-call state.apply elasticfleet queue=True
|
salt-call state.apply elasticfleet queue=True
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ case $1 in
|
|||||||
"elasticfleet"|"elastic-fleet")
|
"elasticfleet"|"elastic-fleet")
|
||||||
docker_check_running "elastic-fleet" "--stop"
|
docker_check_running "elastic-fleet" "--stop"
|
||||||
docker rm "so-elastic-fleet" 2> /dev/null
|
docker rm "so-elastic-fleet" 2> /dev/null
|
||||||
# Removing the elastic fleet state directory, so that the next startup re-enrolls with a fresh policy
|
|
||||||
rm -rf /opt/so/conf/elastic-fleet/state
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
docker_check_running "$1" "--stop"
|
docker_check_running "$1" "--stop"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ LAST_HIGHSTATE_END=$([ -e "/opt/so/log/salt/lasthighstate" ] && date -r /opt/so/
|
|||||||
LAST_HEALTHCHECK_STATE_APPLY=$([ -e "/opt/so/log/salt/state-apply-test" ] && date -r /opt/so/log/salt/state-apply-test +%s || echo 0)
|
LAST_HEALTHCHECK_STATE_APPLY=$([ -e "/opt/so/log/salt/state-apply-test" ] && date -r /opt/so/log/salt/state-apply-test +%s || echo 0)
|
||||||
# SETTING THRESHOLD TO ANYTHING UNDER 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default
|
# SETTING THRESHOLD TO ANYTHING UNDER 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default
|
||||||
# THRESHOLD is derived from the salt schedule highstate interval + 1 hour, so the minion-check grace period tracks the schedule automatically.
|
# THRESHOLD is derived from the salt schedule highstate interval + 1 hour, so the minion-check grace period tracks the schedule automatically.
|
||||||
THRESHOLD=$(( ({{ SCHEDULEMERGED.highstate_interval_hours }} + 1) * 3600 )) #within how many seconds the file /opt/so/log/salt/state-apply-test must have been touched/modified before the salt minion is restarted
|
THRESHOLD=$(( ({{ SCHEDULEMERGED.highstate_interval_minutes }} + 60) * 60 )) #within how many seconds the file /opt/so/log/salt/state-apply-test must have been touched/modified before the salt minion is restarted
|
||||||
THRESHOLD_DATE=$((LAST_HEALTHCHECK_STATE_APPLY+THRESHOLD))
|
THRESHOLD_DATE=$((LAST_HEALTHCHECK_STATE_APPLY+THRESHOLD))
|
||||||
|
|
||||||
logCmd() {
|
logCmd() {
|
||||||
|
|||||||
@@ -11,10 +11,6 @@
|
|||||||
|
|
||||||
{# This value is generated during node install and stored in minion pillar #}
|
{# This value is generated during node install and stored in minion pillar #}
|
||||||
{% set SERVICETOKEN = salt['pillar.get']('elasticfleet:config:server:es_token','') %}
|
{% set SERVICETOKEN = salt['pillar.get']('elasticfleet:config:server:es_token','') %}
|
||||||
{# Prevent Elastic Agent from re-enrolling with a new agent.id everytime the container starts up.
|
|
||||||
- if a fresh enrollment is needed use 'so-stop elasticfleet'
|
|
||||||
#}
|
|
||||||
{% set ENROLLED = salt['file.file_exists']('/opt/so/conf/elastic-fleet/state/fleet.enc') %}
|
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- ca
|
- ca
|
||||||
@@ -70,7 +66,6 @@ so-elastic-fleet:
|
|||||||
- /etc/pki/elasticfleet-server.crt:/etc/pki/elasticfleet-server.crt:ro
|
- /etc/pki/elasticfleet-server.crt:/etc/pki/elasticfleet-server.crt:ro
|
||||||
- /etc/pki/elasticfleet-server.key:/etc/pki/elasticfleet-server.key:ro
|
- /etc/pki/elasticfleet-server.key:/etc/pki/elasticfleet-server.key:ro
|
||||||
- /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro
|
- /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro
|
||||||
- /opt/so/conf/elastic-fleet/state:/usr/share/elastic-agent/state
|
|
||||||
- /opt/so/log/elasticfleet:/usr/share/elastic-agent/logs
|
- /opt/so/log/elasticfleet:/usr/share/elastic-agent/logs
|
||||||
{% if DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %}
|
{% if DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %}
|
||||||
{% for BIND in DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %}
|
{% for BIND in DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %}
|
||||||
@@ -78,7 +73,6 @@ so-elastic-fleet:
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
- environment:
|
- environment:
|
||||||
{% if not ENROLLED %}
|
|
||||||
- FLEET_SERVER_ENABLE=true
|
- FLEET_SERVER_ENABLE=true
|
||||||
- FLEET_URL=https://{{ GLOBALS.hostname }}:8220
|
- FLEET_URL=https://{{ GLOBALS.hostname }}:8220
|
||||||
- FLEET_SERVER_ELASTICSEARCH_HOST=https://{{ GLOBALS.manager }}:9200
|
- FLEET_SERVER_ELASTICSEARCH_HOST=https://{{ GLOBALS.manager }}:9200
|
||||||
@@ -88,9 +82,6 @@ so-elastic-fleet:
|
|||||||
- FLEET_SERVER_CERT_KEY=/etc/pki/elasticfleet-server.key
|
- FLEET_SERVER_CERT_KEY=/etc/pki/elasticfleet-server.key
|
||||||
- FLEET_CA=/etc/pki/tls/certs/intca.crt
|
- FLEET_CA=/etc/pki/tls/certs/intca.crt
|
||||||
- FLEET_SERVER_ELASTICSEARCH_CA=/etc/pki/tls/certs/intca.crt
|
- FLEET_SERVER_ELASTICSEARCH_CA=/etc/pki/tls/certs/intca.crt
|
||||||
{% endif %}
|
|
||||||
- STATE_PATH=/usr/share/elastic-agent/state
|
|
||||||
- CONFIG_PATH=/usr/share/elastic-agent/state
|
|
||||||
- LOGS_PATH=logs
|
- LOGS_PATH=logs
|
||||||
{% if DOCKERMERGED.containers['so-elastic-fleet'].extra_env %}
|
{% if DOCKERMERGED.containers['so-elastic-fleet'].extra_env %}
|
||||||
{% for XTRAENV in DOCKERMERGED.containers['so-elastic-fleet'].extra_env %}
|
{% for XTRAENV in DOCKERMERGED.containers['so-elastic-fleet'].extra_env %}
|
||||||
@@ -109,7 +100,6 @@ so-elastic-fleet:
|
|||||||
- x509: etc_elasticfleet_crt
|
- x509: etc_elasticfleet_crt
|
||||||
- require:
|
- require:
|
||||||
- file: trusttheca
|
- file: trusttheca
|
||||||
- file: eastatedir
|
|
||||||
- x509: etc_elasticfleet_key
|
- x509: etc_elasticfleet_key
|
||||||
- x509: etc_elasticfleet_crt
|
- x509: etc_elasticfleet_crt
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
esheap: '600m'
|
||||||
version: 9.3.7
|
version: 9.3.7
|
||||||
index_clean: true
|
index_clean: true
|
||||||
data_retention_method: DLM
|
data_retention_method: DLM
|
||||||
|
|||||||
@@ -150,6 +150,16 @@ logrotate:
|
|||||||
- extension .log
|
- extension .log
|
||||||
- dateext
|
- dateext
|
||||||
- dateyesterday
|
- dateyesterday
|
||||||
|
/opt/so/log/postgres/*_x_log:
|
||||||
|
- daily
|
||||||
|
- rotate 14
|
||||||
|
- missingok
|
||||||
|
- copytruncate
|
||||||
|
- compress
|
||||||
|
- create
|
||||||
|
- extension .log
|
||||||
|
- dateext
|
||||||
|
- dateyesterday
|
||||||
/opt/so/log/telegraf/*_x_log:
|
/opt/so/log/telegraf/*_x_log:
|
||||||
- daily
|
- daily
|
||||||
- rotate 14
|
- rotate 14
|
||||||
|
|||||||
@@ -91,6 +91,13 @@ logrotate:
|
|||||||
multiline: True
|
multiline: True
|
||||||
global: True
|
global: True
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
|
"/opt/so/log/postgres/*_x_log":
|
||||||
|
description: List of logrotate options for this file.
|
||||||
|
title: /opt/so/log/postgres/*.log
|
||||||
|
advanced: True
|
||||||
|
multiline: True
|
||||||
|
global: True
|
||||||
|
forcedType: "[]string"
|
||||||
"/opt/so/log/telegraf/*_x_log":
|
"/opt/so/log/telegraf/*_x_log":
|
||||||
description: List of logrotate options for this file.
|
description: List of logrotate options for this file.
|
||||||
title: /opt/so/log/telegraf/*.log
|
title: /opt/so/log/telegraf/*.log
|
||||||
|
|||||||
@@ -442,7 +442,13 @@ get_soup_script_hashes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
highstate() {
|
highstate() {
|
||||||
# Run a highstate.
|
# Run a highstate with a retry attempt.
|
||||||
|
if salt-call state.highstate -l info queue=True; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Initial highstate attempt had a problem; retrying in 30 seconds."
|
||||||
|
sleep 30
|
||||||
salt-call state.highstate -l info queue=True
|
salt-call state.highstate -l info queue=True
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,29 +886,21 @@ recollate_postgres() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap_so_soc_database() {
|
scrub_postgres_log_passwords() {
|
||||||
# init-db.sh is mounted into so-postgres at /docker-entrypoint-initdb.d/init-db.sh
|
# Purge plaintext passwords a pre-3.2 postgres could log on DDL errors.
|
||||||
# and runs automatically only on a fresh data directory. Hosts upgrading from
|
local log=/opt/so/log/postgres/postgres.log
|
||||||
# 3.1.0 already have /nsm/postgres populated, so the so_soc bootstrap block
|
[[ -f "$log" ]] || return 0
|
||||||
# added in 3.2 never fires. Re-run the script explicitly; it's idempotent.
|
if ! grep -qai "PASSWORD '" "$log" 2>/dev/null; then
|
||||||
echo "Bootstrapping database via init-db.sh."
|
echo "No leaked passwords found in $log."
|
||||||
# The postgres image has no USER directive, so `docker exec` defaults to
|
|
||||||
# root, and the container env intentionally omits POSTGRES_USER (the upstream
|
|
||||||
# entrypoint defaults it transiently during first-init only). Recreate both
|
|
||||||
# so psql inside init-db.sh resolves the connect user correctly.
|
|
||||||
local exec_cmd="docker exec -u postgres -e POSTGRES_USER=postgres so-postgres bash /docker-entrypoint-initdb.d/init-db.sh"
|
|
||||||
if ! /usr/sbin/so-postgres-wait; then
|
|
||||||
FINAL_MESSAGE_QUEUE+=("WARNING: so-postgres was not ready during the 3.2.0 upgrade; the so_soc database may not have been bootstrapped. Re-run manually: $exec_cmd")
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if ! $exec_cmd; then
|
echo "Removing leaked password statements from $log."
|
||||||
FINAL_MESSAGE_QUEUE+=("WARNING: init-db.sh failed inside so-postgres during the 3.2.0 upgrade; the database may not have been bootstrapped. Re-run manually: $exec_cmd")
|
local tmp
|
||||||
return 0
|
tmp=$(mktemp)
|
||||||
fi
|
# Rewrite in place (cat >) to keep the inode postgres is writing to.
|
||||||
echo "Database bootstrap complete."
|
grep -avi "PASSWORD '" "$log" > "$tmp" 2>/dev/null || true
|
||||||
|
cat "$tmp" > "$log"
|
||||||
echo "Restarting so-soc container to pick up database changes"
|
rm -f "$tmp"
|
||||||
docker restart so-soc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Existing grids should keep ILM unless an admin explicitly opts in to DLM.
|
# Existing grids should keep ILM unless an admin explicitly opts in to DLM.
|
||||||
@@ -982,6 +980,10 @@ up_to_3.2.0() {
|
|||||||
|
|
||||||
pin_elasticsearch_data_retention_method
|
pin_elasticsearch_data_retention_method
|
||||||
|
|
||||||
|
# Run so-elastic-fleet-es-url update with --force to ensure eval/import have
|
||||||
|
# configured so-manager_elasicsearch as the default output for both monitoring and logs
|
||||||
|
/usr/sbin/so-elastic-fleet-es-url-update --force
|
||||||
|
|
||||||
INSTALLEDVERSION=3.2.0
|
INSTALLEDVERSION=3.2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,7 +991,8 @@ post_to_3.2.0() {
|
|||||||
# Recollate due to image OS rebase
|
# Recollate due to image OS rebase
|
||||||
recollate_postgres
|
recollate_postgres
|
||||||
|
|
||||||
bootstrap_so_soc_database
|
# SOC database bootstrap is handled by the postgres.enabled highstate.
|
||||||
|
scrub_postgres_log_passwords
|
||||||
|
|
||||||
# Generate 9.3.7 elastic agent installers
|
# Generate 9.3.7 elastic agent installers
|
||||||
echo "Regenerating Elastic Agent Installers"
|
echo "Regenerating Elastic Agent Installers"
|
||||||
@@ -2005,11 +2008,11 @@ main() {
|
|||||||
# Testing that salt-master is up by checking that is it connected to itself
|
# Testing that salt-master is up by checking that is it connected to itself
|
||||||
check_saltmaster_status
|
check_saltmaster_status
|
||||||
|
|
||||||
# update the salt-minion configs here and start the minion
|
# update the salt-master and salt-minion configs here and start the minion
|
||||||
# since highstate are disabled above, minion start should not trigger a highstate
|
# since highstate are disabled above, minion start should not trigger a highstate
|
||||||
echo ""
|
echo ""
|
||||||
echo "Ensuring salt-minion configs are up-to-date."
|
echo "Ensuring salt-master and salt-minion configs are up-to-date."
|
||||||
salt-call state.apply salt.minion -l info queue=True
|
salt-call state.apply salt.master -l info queue=True
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 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
|
||||||
|
|||||||
@@ -85,6 +85,23 @@ so-postgres:
|
|||||||
- x509: postgres_crt
|
- x509: postgres_crt
|
||||||
- x509: postgres_key
|
- x509: postgres_key
|
||||||
|
|
||||||
|
postgres_wait_ready:
|
||||||
|
cmd.run:
|
||||||
|
- name: /usr/sbin/so-postgres-wait
|
||||||
|
- require:
|
||||||
|
- docker_container: so-postgres
|
||||||
|
- file: postgres_sbin
|
||||||
|
|
||||||
|
# Reconcile the SOC database (role, grants, so_telegraf) every highstate so a
|
||||||
|
# partially-initialized cluster self-heals. POSTGRES_USER is injected because
|
||||||
|
# the container env omits it.
|
||||||
|
postgres_bootstrap_soc_db:
|
||||||
|
cmd.run:
|
||||||
|
- name: docker exec -u postgres -e POSTGRES_USER=postgres so-postgres bash /docker-entrypoint-initdb.d/init-db.sh
|
||||||
|
- require:
|
||||||
|
- cmd: postgres_wait_ready
|
||||||
|
- file: postgresinitdb
|
||||||
|
|
||||||
delete_so-postgres_so-status.disabled:
|
delete_so-postgres_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
|
||||||
|
|||||||
@@ -8,13 +8,17 @@ if [ -z "${SO_POSTGRES_PASS:-}" ] && [ -n "${SO_POSTGRES_PASS_FILE:-}" ] && [ -r
|
|||||||
SO_POSTGRES_PASS="$(< "$SO_POSTGRES_PASS_FILE")"
|
SO_POSTGRES_PASS="$(< "$SO_POSTGRES_PASS_FILE")"
|
||||||
fi
|
fi
|
||||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
-- Keep the password out of postgres.log if this DDL errors.
|
||||||
|
SET log_min_error_statement = panic;
|
||||||
|
-- Idempotent, race-safe upsert: CREATE, falling back to ALTER if the role
|
||||||
|
-- already exists or is created concurrently.
|
||||||
DO \$\$
|
DO \$\$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${SO_POSTGRES_USER}') THEN
|
BEGIN
|
||||||
EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
||||||
ELSE
|
EXCEPTION WHEN duplicate_object OR unique_violation THEN
|
||||||
EXECUTE format('ALTER ROLE %I WITH PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
||||||
END IF;
|
END;
|
||||||
END
|
END
|
||||||
\$\$;
|
\$\$;
|
||||||
GRANT ALL ON SCHEMA public TO "$SO_POSTGRES_USER";
|
GRANT ALL ON SCHEMA public TO "$SO_POSTGRES_USER";
|
||||||
|
|||||||
@@ -8,23 +8,14 @@
|
|||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'telegraf/map.jinja' import TELEGRAFMERGED %}
|
{% from 'telegraf/map.jinja' import TELEGRAFMERGED %}
|
||||||
|
|
||||||
{# postgres_wait_ready below requires `docker_container: so-postgres`, which is
|
{# postgres.enabled declares the so-postgres container and postgres_wait_ready
|
||||||
declared in postgres.enabled. Include it here so state.apply postgres.telegraf_users
|
that the requires below reference. Salt de-duplicates the circular include. #}
|
||||||
on its own (e.g. from orch.deploy_newnode) still has that ID in scope. Salt
|
|
||||||
de-duplicates the circular include. #}
|
|
||||||
include:
|
include:
|
||||||
- postgres.enabled
|
- postgres.enabled
|
||||||
|
|
||||||
{% set TG_OUT = TELEGRAFMERGED.output | upper %}
|
{% set TG_OUT = TELEGRAFMERGED.output | upper %}
|
||||||
{% if TG_OUT in ['POSTGRES', 'BOTH'] %}
|
{% if TG_OUT in ['POSTGRES', 'BOTH'] %}
|
||||||
|
|
||||||
postgres_wait_ready:
|
|
||||||
cmd.run:
|
|
||||||
- name: /usr/sbin/so-postgres-wait
|
|
||||||
- require:
|
|
||||||
- docker_container: so-postgres
|
|
||||||
- file: postgres_sbin
|
|
||||||
|
|
||||||
# Ensure the shared Telegraf database exists. init-db.sh only runs on a
|
# Ensure the shared Telegraf database exists. init-db.sh only runs on a
|
||||||
# fresh data dir, so hosts upgraded onto an existing /nsm/postgres volume
|
# fresh data dir, so hosts upgraded onto an existing /nsm/postgres volume
|
||||||
# would otherwise never get so_telegraf.
|
# would otherwise never get so_telegraf.
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ EOSQL
|
|||||||
-v role_user="$ROLE_USER" \
|
-v role_user="$ROLE_USER" \
|
||||||
-v role_pass="$ROLE_PASS" \
|
-v role_pass="$ROLE_PASS" \
|
||||||
-U postgres -d so_telegraf <<'EOSQL'
|
-U postgres -d so_telegraf <<'EOSQL'
|
||||||
|
-- Keep the password out of postgres.log if this DDL errors.
|
||||||
|
SET log_min_error_statement = panic;
|
||||||
SELECT format(
|
SELECT format(
|
||||||
CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :'role_user')
|
CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :'role_user')
|
||||||
THEN 'ALTER ROLE %I WITH LOGIN PASSWORD %L'
|
THEN 'ALTER ROLE %I WITH LOGIN PASSWORD %L'
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ versionlock:
|
|||||||
# grain (compound supports nested grain matching via G@<key>:<subkey>:<value>).
|
# grain (compound supports nested grain matching via G@<key>:<subkey>:<value>).
|
||||||
# pillar/vm/soc_vm.sls write path is referenced at salt/_runners/setup_hypervisor.py:856.
|
# pillar/vm/soc_vm.sls write path is referenced at salt/_runners/setup_hypervisor.py:856.
|
||||||
vm:
|
vm:
|
||||||
- state: vm
|
- state: vm.user
|
||||||
tgt: 'G@salt-cloud:driver:libvirt'
|
tgt: 'G@salt-cloud:driver:libvirt'
|
||||||
|
|
||||||
# zeek: sensor_roles + so-import (5 roles).
|
# zeek: sensor_roles + so-import (5 roles).
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ so_repo:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
- gpgcheck: 1
|
- gpgcheck: 1
|
||||||
|
{% if not GLOBALS.is_manager %}
|
||||||
|
- sslverify: 0
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Only assign the kernel repo once this node's running salt matches the version this
|
# Only assign the kernel repo once this node's running salt matches the version this
|
||||||
# SO release ships. During a soup the grid is mid-salt-upgrade; gating here keeps the
|
# SO release ships. During a soup the grid is mid-salt-upgrade; gating here keeps the
|
||||||
@@ -77,6 +80,9 @@ so_kernel_repo:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
- gpgcheck: 1
|
- gpgcheck: 1
|
||||||
|
{% if not GLOBALS.is_manager %}
|
||||||
|
- sslverify: 0
|
||||||
|
{% endif %}
|
||||||
# Supplementary kernel repo: tolerate it being empty/unreachable (e.g. before the
|
# Supplementary kernel repo: tolerate it being empty/unreachable (e.g. before the
|
||||||
# manager has populated /nsm/kernelrepo) so a missing repomd.xml can't make every
|
# manager has populated /nsm/kernelrepo) so a missing repomd.xml can't make every
|
||||||
# dnf/pkg operation on the grid fail.
|
# dnf/pkg operation on the grid fail.
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ salt:
|
|||||||
batch: '25%'
|
batch: '25%'
|
||||||
batch_wait: 15
|
batch_wait: 15
|
||||||
schedule:
|
schedule:
|
||||||
highstate_interval_hours: 2
|
highstate_interval_minutes: 120
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'salt/schedule.map.jinja' import SCHEDULEMERGED %}
|
{% from 'salt/schedule.map.jinja' import SCHEDULEMERGED %}
|
||||||
|
|
||||||
|
{# splay a quarter of the interval, clamped to [5 min, 30 min], so short intervals
|
||||||
|
don't get jitter larger than the interval itself #}
|
||||||
|
{% set SPLAY = [[(SCHEDULEMERGED.highstate_interval_minutes * 60 // 4) | int, 300] | max, 1800] | min %}
|
||||||
|
|
||||||
highstate_schedule:
|
highstate_schedule:
|
||||||
schedule.present:
|
schedule.present:
|
||||||
- function: state.highstate
|
- function: state.highstate
|
||||||
- hours: {{ SCHEDULEMERGED.highstate_interval_hours }}
|
- minutes: {{ SCHEDULEMERGED.highstate_interval_minutes }}
|
||||||
- maxrunning: 1
|
- maxrunning: 1
|
||||||
{% if not GLOBALS.is_manager %}
|
{% if not GLOBALS.is_manager %}
|
||||||
- splay: 1800
|
- splay: {{ SPLAY }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ salt_master_service:
|
|||||||
- file: checkmine_engine
|
- file: checkmine_engine
|
||||||
- file: pillarWatch_engine
|
- file: pillarWatch_engine
|
||||||
- file: engines_config
|
- file: engines_config
|
||||||
- order: 9002
|
- require:
|
||||||
|
- cmd: wait_for_salt_minion_ready
|
||||||
|
- order: last
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ salt:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
schedule:
|
schedule:
|
||||||
highstate_interval_hours:
|
highstate_interval_minutes:
|
||||||
description: How often every minion in the grid runs a scheduled state.highstate, in hours. Lower values keep minions closer in sync at the cost of more load; higher values reduce load but increase worst-case latency for non-pushed changes. The salt-minion health check restarts a minion if its last highstate is older than this value plus one hour.
|
description: How often every minion in the grid runs a scheduled state.highstate, in minutes. Minimum 15 minutes. Lower values keep minions closer in sync at the cost of more load; higher values reduce load but increase worst-case latency for non-pushed changes. If Auto Apply is disabled, set this to the 15-minute minimum so changes are still picked up promptly. The salt-minion health check restarts a minion if its last state apply is older than this value plus one hour.
|
||||||
forcedType: int
|
forcedType: int
|
||||||
helpLink: push
|
helpLink: push
|
||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
|
regex: '^(1[5-9]|[2-9][0-9]|[1-9][0-9]{2,4})$'
|
||||||
|
regexFailureMessage: The value must be an integer of at least 15 minutes (maximum 99999).
|
||||||
|
|||||||
+18
-4
@@ -1512,6 +1512,10 @@ soc:
|
|||||||
rulesetName: sos-resources-ag
|
rulesetName: sos-resources-ag
|
||||||
branch: main
|
branch: main
|
||||||
folder: securityonion-normalized
|
folder: securityonion-normalized
|
||||||
|
- repo: file:///nsm/airgap-resources/playbooks/securityonion-resources-playbooks
|
||||||
|
rulesetName: sos-published-ag
|
||||||
|
branch: published
|
||||||
|
folder: sigma
|
||||||
assistant:
|
assistant:
|
||||||
systemPromptAddendum: ""
|
systemPromptAddendum: ""
|
||||||
systemPromptAddendumMaxLength: 50000
|
systemPromptAddendumMaxLength: 50000
|
||||||
@@ -1530,16 +1534,16 @@ soc:
|
|||||||
healthTimeoutSeconds: 5
|
healthTimeoutSeconds: 5
|
||||||
agentic: false
|
agentic: false
|
||||||
agentMapping:
|
agentMapping:
|
||||||
Orchestrator: sonnet
|
Orchestrator: Claude Sonnet
|
||||||
Investigator: sonnet
|
Investigator: Claude Sonnet
|
||||||
Detection Engineer: sonnet
|
DetectionEngineer: Claude Sonnet
|
||||||
onionconfig:
|
onionconfig:
|
||||||
saltstackDir: /opt/so/saltstack
|
saltstackDir: /opt/so/saltstack
|
||||||
bypassEnabled: false
|
bypassEnabled: false
|
||||||
postgres:
|
postgres:
|
||||||
host: ""
|
host: ""
|
||||||
port: 5432
|
port: 5432
|
||||||
sslMode: "allow"
|
sslMode: "require"
|
||||||
database: securityonion
|
database: securityonion
|
||||||
user: ""
|
user: ""
|
||||||
password: ""
|
password: ""
|
||||||
@@ -2714,4 +2718,14 @@ soc:
|
|||||||
enabled: true
|
enabled: true
|
||||||
adapter: SOAI
|
adapter: SOAI
|
||||||
charsPerTokenEstimate: 4
|
charsPerTokenEstimate: 4
|
||||||
|
- id: gemma
|
||||||
|
displayName: Gemma
|
||||||
|
origin: USA
|
||||||
|
contextLimitSmall: 256000
|
||||||
|
contextLimitLarge: 256000
|
||||||
|
lowBalanceColorAlert: 500000
|
||||||
|
enabled: true
|
||||||
|
adapter: SOAI
|
||||||
|
charsPerTokenEstimate: 4
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,18 +14,22 @@
|
|||||||
|
|
||||||
CommandLine: process.command_line
|
CommandLine: process.command_line
|
||||||
CurrentDirectory: process.working_directory
|
CurrentDirectory: process.working_directory
|
||||||
|
Details: registry.data.strings
|
||||||
Image: process.executable
|
Image: process.executable
|
||||||
ImageLoaded: dll.name
|
ImageLoaded: dll.path
|
||||||
ParentImage: process.parent.executable
|
ParentImage: process.parent.executable
|
||||||
ParentName: process.parent.name
|
ParentName: process.parent.name
|
||||||
ParentProcessGuid: process.parent.entity_id
|
ParentProcessGuid: process.parent.entity_id
|
||||||
ProcessGuid: process.entity_id
|
ProcessGuid: process.entity_id
|
||||||
TargetFilename: file.name
|
TargetFilename: file.path
|
||||||
TargetObject: registry.path
|
TargetObject: registry.path
|
||||||
TargetUserName: user.target.name
|
TargetUserName: user.target.name
|
||||||
User: user.name
|
User: user.name
|
||||||
community_id: network.community_id
|
community_id: network.community_id
|
||||||
dns_resolved_ip: dns.resolved_ip
|
dns_resolved_ip: dns.resolved_ip
|
||||||
|
QueryName: dns.question.name
|
||||||
|
dll_basename: dll.name
|
||||||
|
file_basename: file.name
|
||||||
document_id: soc_id
|
document_id: soc_id
|
||||||
dst_ip: destination.ip
|
dst_ip: destination.ip
|
||||||
dst_port: destination.port
|
dst_port: destination.port
|
||||||
@@ -40,10 +44,15 @@ public_ip: network.public_ip
|
|||||||
related_hosts: related.hosts
|
related_hosts: related.hosts
|
||||||
related_ip: related.ip
|
related_ip: related.ip
|
||||||
src_ip: source.ip
|
src_ip: source.ip
|
||||||
dns_query_name: dns.query_name
|
dns_query_name: dns.question.name
|
||||||
flow_id: log.id.uid
|
flow_id: log.id.uid
|
||||||
payload: network.data.decoded
|
payload: network.data.decoded
|
||||||
rule_category: rule.category
|
rule_category: rule.category
|
||||||
rule_name: rule.name
|
rule_name: rule.name
|
||||||
rule_uuid: rule.uuid
|
rule_uuid: rule.uuid
|
||||||
src_port: source.port
|
src_port: source.port
|
||||||
|
# PowerShell channel (ps_script EID 4104 / classic EID 400)
|
||||||
|
ScriptBlockText: powershell.file.script_block_text
|
||||||
|
script_block_id: powershell.file.script_block_id
|
||||||
|
script_block_hash: powershell.file.script_block_hash
|
||||||
|
EngineVersion: powershell.engine.version
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
name: Security Onion - Playbook Pipeline
|
name: Security Onion - Playbook Pipeline
|
||||||
priority: 97
|
priority: 97
|
||||||
transformations:
|
transformations:
|
||||||
# Route string fields to their lowercase-normalized .caseless subfield so wildcard
|
# Route to lowercase-normalized .caseless subfields for case-insensitive matching.
|
||||||
# matches are case-insensitive.
|
# file.path.caseless exists on Defend only (Sysmon file events lack it);
|
||||||
|
# registry.path / dll.path / file.name have no .caseless on any source.
|
||||||
- id: case_insensitive_string_fields
|
- id: case_insensitive_string_fields
|
||||||
type: field_name_mapping
|
type: field_name_mapping
|
||||||
mapping:
|
mapping:
|
||||||
@@ -10,3 +11,145 @@ transformations:
|
|||||||
process.parent.executable: process.parent.executable.caseless
|
process.parent.executable: process.parent.executable.caseless
|
||||||
process.command_line: process.command_line.caseless
|
process.command_line: process.command_line.caseless
|
||||||
process.parent.command_line: process.parent.command_line.caseless
|
process.parent.command_line: process.parent.command_line.caseless
|
||||||
|
file.path: file.path.caseless
|
||||||
|
# entity_id pivots must also match processes that were already running when the
|
||||||
|
# agent started: Defend emits already_running (event.type:info), not start.
|
||||||
|
# Kept out of Playbook sigma query because Sysmon has no equivalent concept.
|
||||||
|
# contains_field is exact, so child pivots (process.parent.entity_id) stay
|
||||||
|
# start-only. Drop must precede add;
|
||||||
|
- id: playbook_process_lifecycle_drop_start_scope
|
||||||
|
type: drop_detection_item
|
||||||
|
field_name_conditions:
|
||||||
|
- type: include_fields
|
||||||
|
fields: ['event.type']
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: process_creation
|
||||||
|
- type: contains_field
|
||||||
|
field: process.entity_id
|
||||||
|
- id: playbook_process_lifecycle_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.type: ['start', 'info']
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: process_creation
|
||||||
|
- type: contains_field
|
||||||
|
field: process.entity_id
|
||||||
|
# file_activity: playbook-only pseudo-category spanning all file operations.
|
||||||
|
- id: playbook_file_activity_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'file'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_activity
|
||||||
|
# EventType -> event.action is safe as a projection only — the values differ
|
||||||
|
# (Sysmon DeleteFile/SetValue vs ECS deletion/modification).
|
||||||
|
- id: playbook_file_activity_event_type
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
winlog.event_data.EventType: event.action
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_activity
|
||||||
|
- id: playbook_file_event_event_type
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
winlog.event_data.EventType: event.action
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_event
|
||||||
|
- id: playbook_file_delete_event_type
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
winlog.event_data.EventType: event.action
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_delete
|
||||||
|
- id: playbook_file_rename_event_type
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
winlog.event_data.EventType: event.action
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_rename
|
||||||
|
- id: playbook_registry_set_event_type
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
winlog.event_data.EventType: event.action
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: registry_set
|
||||||
|
# WMI-Activity events carry no event.category; event.dataset is source-specific
|
||||||
|
- id: playbook_wmi_activity_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.dataset: 'wmi.operational'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: wmi
|
||||||
|
- id: playbook_wmi_event_activity_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.dataset: 'wmi.operational'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: wmi_event
|
||||||
|
- id: playbook_ps_script_field-mapping
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
ScriptBlockText: powershell.file.script_block_text
|
||||||
|
Path: file.path
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_script
|
||||||
|
- id: playbook_ps_script_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.dataset: 'windows.powershell_operational'
|
||||||
|
event.code: '4104'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_script
|
||||||
|
# Data (raw EID 400/600 message blob) -> process.command_line: the winlog
|
||||||
|
# integration parses HostApplication into it; `message` is analyzed text and
|
||||||
|
# wildcard matches on it silently return zero. No .caseless on this dataset.
|
||||||
|
- id: playbook_ps_classic_start_field-mapping
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
Data: process.command_line
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_classic_start
|
||||||
|
- id: playbook_ps_classic_start_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.dataset: 'windows.powershell'
|
||||||
|
event.code: '400'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_classic_start
|
||||||
|
- id: playbook_ps_classic_provider_start_field-mapping
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
Data: process.command_line
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_classic_provider_start
|
||||||
|
- id: playbook_ps_classic_provider_start_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.dataset: 'windows.powershell'
|
||||||
|
event.code: '600'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: ps_classic_provider_start
|
||||||
|
# Alert docs nest the host under event_data.host.name; no top-level host.name.
|
||||||
|
- id: playbook_alert_host_field
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
host.name: event_data.host.name
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: alert
|
||||||
|
|||||||
@@ -46,31 +46,47 @@ transformations:
|
|||||||
- type: logsource
|
- type: logsource
|
||||||
product: opencanary
|
product: opencanary
|
||||||
# Maps "antivirus" category to Windows Defender logs shipped by Elastic Agent Winlog Integration
|
# Maps "antivirus" category to Windows Defender logs shipped by Elastic Agent Winlog Integration
|
||||||
|
# and to Elastic Defend malware alerts
|
||||||
# winlog.event_data.threat_name has to be renamed prior to ingestion, it is originally winlog.event_data.Threat Name
|
# winlog.event_data.threat_name has to be renamed prior to ingestion, it is originally winlog.event_data.Threat Name
|
||||||
- id: antivirus_field-mappings_windows-defender
|
- id: antivirus_field-mappings
|
||||||
type: field_name_mapping
|
type: field_name_mapping
|
||||||
mapping:
|
mapping:
|
||||||
Signature: winlog.event_data.threat_name
|
Signature:
|
||||||
|
- winlog.event_data.threat_name
|
||||||
|
- rule.name
|
||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
- type: logsource
|
||||||
category: antivirus
|
category: antivirus
|
||||||
- id: antivirus_add-fields_windows-defender
|
- id: antivirus_add-fields
|
||||||
type: add_condition
|
type: add_condition
|
||||||
conditions:
|
conditions:
|
||||||
winlog.channel: 'Microsoft-Windows-Windows Defender/Operational'
|
event.code:
|
||||||
winlog.provider_name: 'Microsoft-Windows-Windows Defender'
|
- "1116"
|
||||||
event.code: "1116"
|
- "malicious_file"
|
||||||
|
- "memory_signature"
|
||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
- type: logsource
|
||||||
category: antivirus
|
category: antivirus
|
||||||
# OS-agnostic process_creation scoping for product-less (NIDS/host-pivot) rules.
|
# OS-agnostic process_creation scoping for product-less (NIDS/host-pivot) rules.
|
||||||
|
# pySigma: rule_cond_expr requires rule_conditions as a mapping, not a list.
|
||||||
- id: process_creation_os_agnostic
|
- id: process_creation_os_agnostic
|
||||||
type: add_condition
|
type: add_condition
|
||||||
conditions:
|
conditions:
|
||||||
event.category: process
|
event.category: process
|
||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
pc_cat:
|
||||||
|
type: logsource
|
||||||
category: process_creation
|
category: process_creation
|
||||||
|
pc_win:
|
||||||
|
type: logsource
|
||||||
|
product: windows
|
||||||
|
pc_mac:
|
||||||
|
type: logsource
|
||||||
|
product: macos
|
||||||
|
pc_lin:
|
||||||
|
type: logsource
|
||||||
|
product: linux
|
||||||
|
rule_cond_expr: "pc_cat and not (pc_win or pc_mac or pc_lin)"
|
||||||
# Transforms the `Hashes` field to ECS fields
|
# Transforms the `Hashes` field to ECS fields
|
||||||
# ECS fields are used by the hash fields emitted by Elastic Defend
|
# ECS fields are used by the hash fields emitted by Elastic Defend
|
||||||
# If shipped with Elastic Agent, sysmon logs will also have hashes mapped to ECS fields
|
# If shipped with Elastic Agent, sysmon logs will also have hashes mapped to ECS fields
|
||||||
@@ -131,13 +147,22 @@ transformations:
|
|||||||
type: field_name_mapping
|
type: field_name_mapping
|
||||||
mapping:
|
mapping:
|
||||||
winlog.event_data.Details: registry.data.strings
|
winlog.event_data.Details: registry.data.strings
|
||||||
# field rename only; EventType values (SetValue/CreateKey) still differ from
|
|
||||||
# event.action values (modification/creation)
|
|
||||||
winlog.event_data.EventType: event.action
|
|
||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
- type: logsource
|
||||||
product: windows
|
product: windows
|
||||||
category: registry_set
|
category: registry_set
|
||||||
|
# ecs_windows renames Initiated -> network.direction without translating the value,
|
||||||
|
# so rules compile to network.direction:"true" and never match (field holds
|
||||||
|
# ingress/egress). network.initiated carries the boolean on both Defend and Sysmon.
|
||||||
|
# Keyed on network.direction because ecs_windows has already renamed by this layer.
|
||||||
|
- id: ecs_fix_network_connection_initiated
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
network.direction: network.initiated
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
product: windows
|
||||||
|
category: network_connection
|
||||||
- id: ecs_fix_image_load
|
- id: ecs_fix_image_load
|
||||||
type: field_name_mapping
|
type: field_name_mapping
|
||||||
mapping:
|
mapping:
|
||||||
@@ -150,6 +175,30 @@ transformations:
|
|||||||
- type: logsource
|
- type: logsource
|
||||||
product: windows
|
product: windows
|
||||||
category: image_load
|
category: image_load
|
||||||
|
# Defend reports the driver image in dll.path (file.path is null on driver events) —
|
||||||
|
# same renames as image_load.
|
||||||
|
- id: ecs_fix_driver_load
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
file.path: dll.path
|
||||||
|
file.code_signature.signed: dll.code_signature.exists
|
||||||
|
winlog.event_data.Signature: dll.code_signature.subject_name
|
||||||
|
file.code_signature.status: dll.code_signature.status
|
||||||
|
winlog.event_data.Hashes: dll.hash.sha256
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
product: windows
|
||||||
|
category: driver_load
|
||||||
|
- id: ecs_fix_file_rename
|
||||||
|
type: field_name_mapping
|
||||||
|
mapping:
|
||||||
|
# Defend records the pre-rename path in file.Ext.original.path; Sysmon's
|
||||||
|
# SourceFilename has no ECS equivalent.
|
||||||
|
winlog.event_data.SourceFilename: file.Ext.original.path
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
product: windows
|
||||||
|
category: file_rename
|
||||||
- id: linux_security_add-fields
|
- id: linux_security_add-fields
|
||||||
type: add_condition
|
type: add_condition
|
||||||
conditions:
|
conditions:
|
||||||
@@ -323,6 +372,33 @@ transformations:
|
|||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
- type: logsource
|
||||||
category: file_event
|
category: file_event
|
||||||
|
# Without event.type scoping, file_delete rules also match creations.
|
||||||
|
- id: endpoint_file_delete_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'file'
|
||||||
|
event.type: 'deletion'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_delete
|
||||||
|
# Defend reports renames as event.action:rename with event.type:change.
|
||||||
|
- id: endpoint_file_rename_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'file'
|
||||||
|
event.action: 'rename'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_rename
|
||||||
|
# event.type:change selects writes and excludes Defend's read-only registry events.
|
||||||
|
- id: endpoint_registry_set_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'registry'
|
||||||
|
event.type: 'change'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: registry_set
|
||||||
# Scope image_load rules to Elastic Endpoint library events (event.category:library, dll.*
|
# Scope image_load rules to Elastic Endpoint library events (event.category:library, dll.*
|
||||||
# populated).
|
# populated).
|
||||||
- id: endpoint_image_load_add-fields
|
- id: endpoint_image_load_add-fields
|
||||||
@@ -351,6 +427,149 @@ transformations:
|
|||||||
rule_conditions:
|
rule_conditions:
|
||||||
- type: logsource
|
- type: logsource
|
||||||
category: network_connection
|
category: network_connection
|
||||||
|
# Scope on lookup actions, not network.protocol:dns (also matches Zeek port-53).
|
||||||
|
- id: endpoint_dns_query_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'network'
|
||||||
|
event.action:
|
||||||
|
- 'lookup_requested'
|
||||||
|
- 'lookup_result'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: dns_query
|
||||||
|
# OS gates: without them a `product: windows` rule in these categories also matches
|
||||||
|
# Linux/macOS. Separate conditions (not `product:` on the mappings above) so the
|
||||||
|
# mappings keep scoping product-less rules.
|
||||||
|
- id: endpoint_file_create_windows_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'windows'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_event
|
||||||
|
product: windows
|
||||||
|
- id: endpoint_file_create_linux_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'linux'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_event
|
||||||
|
product: linux
|
||||||
|
- id: endpoint_file_create_macos_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'macos'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_event
|
||||||
|
product: macos
|
||||||
|
- id: endpoint_file_delete_windows_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'windows'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_delete
|
||||||
|
product: windows
|
||||||
|
- id: endpoint_file_delete_linux_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'linux'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_delete
|
||||||
|
product: linux
|
||||||
|
- id: endpoint_file_delete_macos_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'macos'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_delete
|
||||||
|
product: macos
|
||||||
|
- id: endpoint_file_rename_windows_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'windows'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_rename
|
||||||
|
product: windows
|
||||||
|
- id: endpoint_file_rename_linux_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'linux'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_rename
|
||||||
|
product: linux
|
||||||
|
- id: endpoint_file_rename_macos_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'macos'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: file_rename
|
||||||
|
product: macos
|
||||||
|
- id: endpoint_network_connection_windows_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'windows'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: network_connection
|
||||||
|
product: windows
|
||||||
|
- id: endpoint_network_connection_linux_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'linux'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: network_connection
|
||||||
|
product: linux
|
||||||
|
- id: endpoint_network_connection_macos_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'macos'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: network_connection
|
||||||
|
product: macos
|
||||||
|
- id: endpoint_dns_query_windows_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'windows'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: dns_query
|
||||||
|
product: windows
|
||||||
|
- id: endpoint_dns_query_linux_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'linux'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: dns_query
|
||||||
|
product: linux
|
||||||
|
- id: endpoint_dns_query_macos_os-gate
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
host.os.type: 'macos'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: dns_query
|
||||||
|
product: macos
|
||||||
|
# registry_set / image_load / driver_load are not gated — windows-only telemetry.
|
||||||
|
# wmi / wmi_event are not scoped here: their only handle is event.dataset
|
||||||
|
- id: endpoint_driver_load_add-fields
|
||||||
|
type: add_condition
|
||||||
|
conditions:
|
||||||
|
event.category: 'driver'
|
||||||
|
rule_conditions:
|
||||||
|
- type: logsource
|
||||||
|
category: driver_load
|
||||||
# Maps "alert" category to SO Alert events
|
# Maps "alert" category to SO Alert events
|
||||||
- id: alert_so_add-fields
|
- id: alert_so_add-fields
|
||||||
type: add_condition
|
type: add_condition
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
'host': GLOBALS.manager_ip,
|
'host': GLOBALS.manager_ip,
|
||||||
'password': PG_PASS,
|
'password': PG_PASS,
|
||||||
'port': 5432,
|
'port': 5432,
|
||||||
'sslMode': 'allow',
|
'sslMode': 'require',
|
||||||
'user': PG_USER,
|
'user': PG_USER,
|
||||||
}
|
}
|
||||||
}) %}
|
}) %}
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ soc:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
sslMode:
|
sslMode:
|
||||||
description: "Use encrypted connections to the PostgreSQL server. Must be one of the following values: disable, allow, prefer, require, verify-ca, verify-full. Defaults to allow."
|
description: "Use encrypted connections to the PostgreSQL server. Must be one of the following values: disable, allow, prefer, require, verify-ca, verify-full."
|
||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
database:
|
database:
|
||||||
@@ -786,7 +786,7 @@ soc:
|
|||||||
Investigator:
|
Investigator:
|
||||||
description: This agent investigates alerts, explains events and records, and hunts through event data. It can also acknowledge alerts and escalate to cases.
|
description: This agent investigates alerts, explains events and records, and hunts through event data. It can also acknowledge alerts and escalate to cases.
|
||||||
global: True
|
global: True
|
||||||
Detection Engineer:
|
DetectionEngineer:
|
||||||
description: This agent manages detections and their overrides, including tuning noisy rules and authoring rule content.
|
description: This agent manages detections and their overrides, including tuning noisy rules and authoring rule content.
|
||||||
global: True
|
global: True
|
||||||
client:
|
client:
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{% import 'vars/init.map.jinja' as INIT %}
|
{% import 'vars/init.map.jinja' as INIT %}
|
||||||
|
{% import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS %}
|
||||||
|
|
||||||
{%
|
{%
|
||||||
set ELASTICSEARCH_GLOBALS = {
|
set ELASTICSEARCH_GLOBALS = {
|
||||||
'elasticsearch': {
|
'elasticsearch': {
|
||||||
'es_cluster_name': INIT.PILLAR.elasticsearch.config.cluster.name,
|
'es_cluster_name': INIT.PILLAR.elasticsearch.config.cluster.name,
|
||||||
'es_heap': INIT.PILLAR.elasticsearch.esheap
|
'es_heap': INIT.PILLAR.elasticsearch.get('esheap', ELASTICSEARCHDEFAULTS.elasticsearch.esheap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ zeek:
|
|||||||
- securityonion/file-extraction
|
- securityonion/file-extraction
|
||||||
- securityonion/community-id-extended
|
- securityonion/community-id-extended
|
||||||
- oui-logging
|
- oui-logging
|
||||||
- icsnpp-modbus
|
|
||||||
- icsnpp-dnp3
|
- icsnpp-dnp3
|
||||||
- icsnpp-bacnet
|
- icsnpp-bacnet
|
||||||
- icsnpp-ethercat
|
- icsnpp-ethercat
|
||||||
|
|||||||
Reference in New Issue
Block a user