mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-07-18 23:03:39 +02:00
Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48a7d66964 | ||
|
|
30f3bddb8b | ||
|
|
6f61e7c901 | ||
|
|
cc2bfc26e2 | ||
|
|
073e32520b | ||
|
|
5867b50720 | ||
|
|
3503d0c33d | ||
|
|
02318f065c | ||
|
|
186bf86e99 | ||
|
|
bd70dd53fb | ||
|
|
be7d8a2aa7 | ||
|
|
618712469e | ||
|
|
8b488f9226 | ||
|
|
1657480d31 | ||
|
|
8167ae3282 | ||
|
|
2cd889782d | ||
|
|
87a5639643 | ||
|
|
99e9fc1c3b | ||
|
|
e5de499bcc | ||
|
|
7d17784e96 | ||
|
|
f0bbbf37d8 | ||
|
|
52885e28c5 | ||
|
|
4e856f02da | ||
|
|
f6a2758321 | ||
|
|
0b078c4804 | ||
|
|
2959dc9564 | ||
|
|
8b0759866e | ||
|
|
6fa0d327cb | ||
|
|
9a71f64a35 | ||
|
|
40c02b3149 | ||
|
|
5fd5df54b4 | ||
|
|
3394e9aab7 | ||
|
|
3766f74102 | ||
|
|
c04a30785f | ||
|
|
ca4d22a5fe | ||
|
|
ea199aee55 | ||
|
|
5a57bbe4de | ||
|
|
9a313d1966 | ||
|
|
85d7f6bebc | ||
|
|
2a4a7307f7 | ||
|
|
f8de176f4b | ||
|
|
70af3cec53 | ||
|
|
57b7d59387 |
@@ -5,53 +5,239 @@
|
|||||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
# Elastic License 2.0.
|
# Elastic License 2.0.
|
||||||
#
|
#
|
||||||
# so-kernel-upgrade — switch the boot default to the installed UEK8 (6.x) kernel.
|
# so-kernel-upgrade — install the UEK8 (6.x) kernel and make it the boot default.
|
||||||
#
|
#
|
||||||
# Security Onion is moving off the EL9 stock kernel / UEK7 (5.x) onto UEK8 (6.x).
|
# Security Onion is moving off the EL9 stock kernel (RHCK, 5.14) and UEK7 (5.15) onto UEK8
|
||||||
# Installing the kernel-uek-core package adds a UEK8 boot entry but does NOT make it the
|
# (6.x). Three things have to happen, and the tool has to drive each one:
|
||||||
# default: kernel-install/grubby only auto-promote a new kernel within the running
|
|
||||||
# kernel's flavor lineage, and we're crossing from a 5.x kernel to the new 6.x UEK flavor.
|
|
||||||
# So even with UPDATEDEFAULT=yes and DEFAULTKERNEL=kernel-uek-core the box keeps booting
|
|
||||||
# the old kernel. This tool finds the newest installed 6.x UEK kernel and makes it the
|
|
||||||
# GRUB default via grubby so the next boot comes up on UEK8.
|
|
||||||
#
|
#
|
||||||
# Idempotent: if the UEK8 kernel is already the default it does nothing. It only sets the
|
# 1. Populate. The manager mirrors the UEK8 packages into /nsm/kernelrepo via so-repo-sync,
|
||||||
# boot default; it does NOT reboot — the admin reboots the node on their own schedule.
|
# and serves them to the grid over https://<manager>/kernelrepo. Until that sync runs the
|
||||||
|
# repo is valid but EMPTY -- dnf resolves it happily and installs nothing, with no error.
|
||||||
|
# 2. Install. A node on RHCK has no kernel-uek* package at all, so there is nothing for
|
||||||
|
# 'dnf update' to upgrade. A node on UEK7 does have kernel-uek installed, so
|
||||||
|
# 'dnf install kernel-uek' reports "Nothing to do" and exits 0 without installing 6.x.
|
||||||
|
# Both cases need an explicit install of the UEK8 NEVRA.
|
||||||
|
# 3. Boot it. Whether a newly installed UEK8 kernel becomes the boot default depends on the
|
||||||
|
# RUNNING kernel's flavor. kernel-install/grubby (with UPDATEDEFAULT=yes) only auto-promote
|
||||||
|
# within the running kernel's flavor lineage:
|
||||||
|
# - From UEK7 (5.x, kernel-uek) the install stays in the kernel-uek lineage and IS
|
||||||
|
# auto-promoted, so no grubby change is needed -- just make sure the repo is populated
|
||||||
|
# and install UEK8.
|
||||||
|
# - From the stock EL9 kernel (RHCK, 5.14, no UEK) it is a flavor CROSS that is NOT
|
||||||
|
# auto-promoted, so the box keeps booting RHCK until grubby is told otherwise.
|
||||||
|
# This tool inspects the running kernel and only runs 'grubby --set-default' for RHCK.
|
||||||
|
#
|
||||||
|
# Every one of those failure modes is silent by default. This tool handles each case and fails
|
||||||
|
# loudly when it cannot, rather than reporting success while changing nothing.
|
||||||
|
#
|
||||||
|
# Manager vs minion: only the manager owns /nsm/kernelrepo, so only the manager can populate
|
||||||
|
# it. If the repo is empty here, a manager runs so-repo-sync itself; a minion has no way to
|
||||||
|
# fix it and exits non-zero telling the admin to sync the manager first.
|
||||||
|
#
|
||||||
|
# Idempotent: an already-installed, already-default UEK8 kernel is left alone. It only sets
|
||||||
|
# the boot default; it does NOT reboot -- the admin reboots the node on their own schedule.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
# Client-side repo id (what dnf enables on this node, from repo/client/oracle.sls) vs the
|
||||||
|
# reposync-side section in repodownload.conf that the manager mirrors from (mirrors the
|
||||||
|
# securityonion/securityonionsync split for the main repo).
|
||||||
|
KERNEL_REPO="securityonionkernel"
|
||||||
|
KERNEL_REPO_SYNC="securityonionkernelsync"
|
||||||
|
KERNEL_PKG="kernel-uek"
|
||||||
|
KERNEL_REPO_DIR="/nsm/kernelrepo"
|
||||||
|
REPOSYNC_CONF="/opt/so/conf/reposync/repodownload.conf"
|
||||||
|
GLOBAL_PILLAR="/opt/so/saltstack/local/pillar/global/soc_global.sls"
|
||||||
|
|
||||||
log() { echo "[so-kernel-upgrade] $*"; }
|
log() { echo "[so-kernel-upgrade] $*"; }
|
||||||
|
die() { echo "[so-kernel-upgrade] ERROR: $*" >&2; exit 1; }
|
||||||
|
|
||||||
[ "$(id -u)" -eq 0 ] || { log "must run as root"; exit 1; }
|
command -v grubby >/dev/null 2>&1 || die "grubby not found"
|
||||||
command -v grubby >/dev/null 2>&1 || { log "grubby not found"; exit 1; }
|
command -v dnf >/dev/null 2>&1 || die "dnf not found"
|
||||||
|
|
||||||
|
ARCH="$(rpm -E '%{_arch}')"
|
||||||
|
|
||||||
|
is_airgap() {
|
||||||
|
[ -f "$GLOBAL_PILLAR" ] && grep -q 'airgap: *[Tt]rue' "$GLOBAL_PILLAR"
|
||||||
|
}
|
||||||
|
|
||||||
# Newest installed UEK8 (6.x) kernel known to the bootloader. UEK8 vmlinuz paths look like
|
# Newest installed UEK8 (6.x) kernel known to the bootloader. UEK8 vmlinuz paths look like
|
||||||
# /boot/vmlinuz-6.12.0-203.76.7.5.el9uek.x86_64; the 5.x UEK7 and 5.14 RHCK won't match.
|
# /boot/vmlinuz-6.12.0-204.92.4.2.el9uek.x86_64; UEK7 (5.15) and RHCK (5.14) won't match.
|
||||||
target="$(grubby --info=ALL 2>/dev/null \
|
find_uek8() {
|
||||||
| sed -n 's/^kernel="\(.*\)"$/\1/p' \
|
grubby --info=ALL 2>/dev/null \
|
||||||
| grep -E '/vmlinuz-6\.[0-9]+.*uek' \
|
| sed -n 's/^kernel="\(.*\)"$/\1/p' \
|
||||||
| sort -V | tail -1)"
|
| grep -E '/vmlinuz-6\.[0-9]+.*uek' \
|
||||||
|
| sort -V | tail -1
|
||||||
|
}
|
||||||
|
|
||||||
if [ -z "$target" ]; then
|
# Classify the RUNNING kernel (uname -r) -- this, not what's installed, is what decides whether
|
||||||
log "no installed 6.x UEK (UEK8) kernel found — confirm the kernel repo is assigned and"
|
# a UEK8 install auto-promotes to the boot default:
|
||||||
log "'dnf update' has installed kernel-uek-core. Nothing to do."
|
# uek8 6.x UEK already on the target line; nothing to do
|
||||||
|
# uek7 5.x UEK a UEK8 install stays in the kernel-uek lineage and auto-promotes (no grubby)
|
||||||
|
# rhck 5.14 EL9 crossing into the UEK flavor does NOT auto-promote (needs grubby --set-default)
|
||||||
|
running_flavor() {
|
||||||
|
case "$(uname -r)" in
|
||||||
|
6.*uek*) echo uek8 ;;
|
||||||
|
*uek*) echo uek7 ;;
|
||||||
|
*) echo rhck ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Newest UEK8 kernel-uek NEVRA offered by the kernel repo, empty if the repo has none.
|
||||||
|
# Restricted to the kernel repo so a UEK7 kernel-uek in the main repo can't be picked up,
|
||||||
|
# and filtered to 6.x so we never "succeed" by reinstalling the 5.15 we already have.
|
||||||
|
uek8_available() {
|
||||||
|
dnf -q repoquery --disablerepo='*' --enablerepo="$KERNEL_REPO" \
|
||||||
|
--arch="$ARCH" --latest-limit=1 \
|
||||||
|
--qf '%{name}-%{evr}.%{arch}\n' "$KERNEL_PKG" 2>/dev/null \
|
||||||
|
| grep -E "^${KERNEL_PKG}-6\." | tail -1
|
||||||
|
}
|
||||||
|
|
||||||
|
kernelrepo_rpm_count() {
|
||||||
|
find "$KERNEL_REPO_DIR" -maxdepth 1 -name '*.rpm' 2>/dev/null | wc -l
|
||||||
|
}
|
||||||
|
|
||||||
|
# The kernel repo starts life as valid-but-empty (kernelrepo_init_empty in
|
||||||
|
# salt/manager/init.sls) and is filled by so-repo-sync. During a soup, so-repo-sync runs
|
||||||
|
# BEFORE the highstate deploys the [securityonionkernelsync] section into repodownload.conf, so
|
||||||
|
# the first kernel-aware soup leaves the repo empty until the next nightly sync.
|
||||||
|
sync_kernel_repo() {
|
||||||
|
if is_airgap; then
|
||||||
|
log "airgap install: $KERNEL_REPO_DIR is populated from the airgap ISO, not by so-repo-sync."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! grep -q "^\[${KERNEL_REPO_SYNC}\]" "$REPOSYNC_CONF" 2>/dev/null; then
|
||||||
|
log "$REPOSYNC_CONF has no [${KERNEL_REPO_SYNC}] section -- run a highstate to deploy it."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "populating $KERNEL_REPO_DIR with so-repo-sync (mirrors upstream; can take several minutes)"
|
||||||
|
su socore -c '/usr/sbin/so-repo-sync' || { log "so-repo-sync failed"; return 1; }
|
||||||
|
|
||||||
|
dnf -q clean expire-cache >/dev/null 2>&1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make the kernel repo actually able to serve a UEK8 package, or fail trying.
|
||||||
|
ensure_kernel_repo() {
|
||||||
|
# The repo is assigned by the repo.client highstate, and only once NICs are pinned by MAC
|
||||||
|
# (/opt/so/state/nic_names_pinned) so the kernel swap can't renumber interfaces SO binds
|
||||||
|
# by name. skip_if_unavailable=1 means a broken repo is silently ignored, so check first.
|
||||||
|
if ! dnf -q repolist --enabled 2>/dev/null | awk '{print $1}' | grep -qx "$KERNEL_REPO"; then
|
||||||
|
log "repo '$KERNEL_REPO' is not enabled on this node."
|
||||||
|
log "Run a highstate first; the repo is skipped until /opt/so/state/nic_names_pinned"
|
||||||
|
log "exists (run so-nic-pin) and this node's salt matches the version this release ships."
|
||||||
|
die "kernel repo unavailable"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -n "$(uek8_available)" ] && return 0
|
||||||
|
|
||||||
|
log "repo '$KERNEL_REPO' is enabled but offers no UEK8 $KERNEL_PKG package"
|
||||||
|
|
||||||
|
if ! is_manager_node; then
|
||||||
|
log "This is a minion; it consumes the kernel repo from the manager and cannot populate it."
|
||||||
|
log "On the manager, run: su socore -c /usr/sbin/so-repo-sync"
|
||||||
|
log "then re-run this script here."
|
||||||
|
die "manager's kernel repo is empty"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "this is a manager and $KERNEL_REPO_DIR holds $(kernelrepo_rpm_count) rpm(s)"
|
||||||
|
sync_kernel_repo || die "could not populate $KERNEL_REPO_DIR"
|
||||||
|
|
||||||
|
[ -n "$(uek8_available)" ] \
|
||||||
|
|| die "so-repo-sync completed but $KERNEL_REPO still offers no UEK8 $KERNEL_PKG"
|
||||||
|
}
|
||||||
|
|
||||||
|
reboot_notice() {
|
||||||
|
[ "$(uname -r)" = "$(basename "$1" | sed 's/^vmlinuz-//')" ] \
|
||||||
|
|| log "REBOOT REQUIRED to start using the UEK8 kernel (currently running $(uname -r))."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep future kernel updates on the UEK line rather than falling back to RHCK. Oracle ships
|
||||||
|
# /etc/sysconfig/kernel; only rewrite it when it's actually pointing somewhere else.
|
||||||
|
set_default_kernel_conf() {
|
||||||
|
if [ -f /etc/sysconfig/kernel ] && ! grep -q '^DEFAULTKERNEL=kernel-uek-core$' /etc/sysconfig/kernel; then
|
||||||
|
log "setting DEFAULTKERNEL=kernel-uek-core in /etc/sysconfig/kernel"
|
||||||
|
sed -i 's/^DEFAULTKERNEL=.*/DEFAULTKERNEL=kernel-uek-core/' /etc/sysconfig/kernel
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make sure a UEK8 kernel is installed, leaving its boot entry in INSTALLED_UEK8. If one is
|
||||||
|
# already present we leave the repo alone -- it may be disabled or empty and we don't need it
|
||||||
|
# just to flip the boot default. Otherwise install the explicit NEVRA, not the bare package
|
||||||
|
# name: on a UEK7 node 'dnf install kernel-uek' sees 5.15 already present, prints "Nothing to
|
||||||
|
# do" and exits 0 without installing 6.x.
|
||||||
|
ensure_uek8_installed() {
|
||||||
|
INSTALLED_UEK8="$(find_uek8)"
|
||||||
|
if [ -n "$INSTALLED_UEK8" ]; then
|
||||||
|
log "UEK8 kernel already installed: $INSTALLED_UEK8"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_kernel_repo
|
||||||
|
local nevra; nevra="$(uek8_available)"
|
||||||
|
log "installing $nevra from $KERNEL_REPO"
|
||||||
|
dnf -y install "$nevra" || die "failed to install $nevra"
|
||||||
|
|
||||||
|
INSTALLED_UEK8="$(find_uek8)"
|
||||||
|
[ -n "$INSTALLED_UEK8" ] || die "$nevra installed but no 6.x UEK boot entry appeared -- check 'grubby --info=ALL'"
|
||||||
|
log "installed UEK8 kernel: $INSTALLED_UEK8"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$(running_flavor)" in
|
||||||
|
uek8)
|
||||||
|
# Already on the 6.x UEK line. A plain 'dnf update' keeps this node current within the
|
||||||
|
# lineage and auto-promotes newer builds, so there is nothing for this tool to do.
|
||||||
|
log "already running a UEK8 kernel ($(uname -r)); nothing to do."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
;;
|
||||||
|
|
||||||
current="$(grubby --default-kernel 2>/dev/null)"
|
uek7)
|
||||||
if [ "$current" = "$target" ]; then
|
# On a 5.x UEK kernel. Installing UEK8 stays inside the kernel-uek lineage, so dnf/grubby
|
||||||
log "UEK8 kernel is already the boot default: $target"
|
# (UPDATEDEFAULT=yes) auto-promote it and we do NOT touch grubby. A node still on UEK7
|
||||||
exit 0
|
# usually means the kernel repo was empty when it last updated, so populate it and install.
|
||||||
fi
|
log "running UEK7 kernel ($(uname -r)); the kernel repo was likely not yet populated when"
|
||||||
|
log "this node last updated. Populating it and installing UEK8 -- the update stays on the"
|
||||||
|
log "kernel-uek line, so it becomes the boot default automatically (no grubby change needed)."
|
||||||
|
set_default_kernel_conf
|
||||||
|
ensure_uek8_installed
|
||||||
|
|
||||||
log "current default kernel: ${current:-unknown}"
|
now="$(grubby --default-kernel 2>/dev/null)"
|
||||||
log "switching boot default to UEK8 kernel: $target"
|
if [ "$now" = "$INSTALLED_UEK8" ]; then
|
||||||
grubby --set-default="$target" || { log "ERROR: grubby --set-default failed for $target"; exit 1; }
|
log "boot default auto-promoted to UEK8 kernel: $INSTALLED_UEK8"
|
||||||
|
else
|
||||||
|
log "WARNING: expected the UEK8 kernel to auto-promote but the default is still"
|
||||||
|
log "'${now:-unknown}'. Run 'grubby --set-default=$INSTALLED_UEK8' to force it."
|
||||||
|
fi
|
||||||
|
reboot_notice "$INSTALLED_UEK8"
|
||||||
|
;;
|
||||||
|
|
||||||
# Verify the change actually took before claiming success.
|
rhck)
|
||||||
now="$(grubby --default-kernel 2>/dev/null)"
|
# On the stock EL9 kernel (5.14, no UEK installed). Crossing from RHCK into the UEK flavor
|
||||||
if [ "$now" != "$target" ]; then
|
# does NOT auto-promote -- kernel-install/grubby only auto-promote within the running
|
||||||
log "ERROR: default kernel is still '${now:-unknown}' after set-default"
|
# kernel's flavor lineage -- so after installing we must set the boot default explicitly.
|
||||||
exit 1
|
log "running stock EL9 (RHCK) kernel ($(uname -r)); installing UEK8 and setting it as the"
|
||||||
fi
|
log "boot default explicitly (a RHCK->UEK flavor change does not auto-promote)."
|
||||||
|
set_default_kernel_conf
|
||||||
|
ensure_uek8_installed
|
||||||
|
target="$INSTALLED_UEK8"
|
||||||
|
|
||||||
log "boot default is now $target"
|
current="$(grubby --default-kernel 2>/dev/null)"
|
||||||
log "REBOOT REQUIRED to start using the UEK8 kernel (currently running $(uname -r))."
|
if [ "$current" = "$target" ]; then
|
||||||
|
log "UEK8 kernel is already the boot default: $target"
|
||||||
|
reboot_notice "$target"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "current default kernel: ${current:-unknown}"
|
||||||
|
log "switching boot default to UEK8 kernel: $target"
|
||||||
|
grubby --set-default="$target" || die "grubby --set-default failed for $target"
|
||||||
|
|
||||||
|
# Verify the change actually took before claiming success.
|
||||||
|
now="$(grubby --default-kernel 2>/dev/null)"
|
||||||
|
[ "$now" = "$target" ] || die "default kernel is still '${now:-unknown}' after set-default"
|
||||||
|
|
||||||
|
log "boot default is now $target"
|
||||||
|
reboot_notice "$target"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ 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,6 +29,8 @@ 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"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
elasticfleet:
|
elasticfleet:
|
||||||
enabled: False
|
enabled: False
|
||||||
patch_version: 9.3.3+build202604082258 # Elastic Agent specific patch release.
|
|
||||||
enable_manager_output: True
|
enable_manager_output: True
|
||||||
config:
|
config:
|
||||||
server:
|
server:
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
{# 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
|
||||||
@@ -65,6 +69,7 @@ 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 %}
|
||||||
@@ -72,6 +77,7 @@ 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
|
||||||
@@ -81,6 +87,9 @@ 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 %}
|
||||||
@@ -99,6 +108,7 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"package": {
|
"package": {
|
||||||
"name": "endpoint",
|
"name": "endpoint",
|
||||||
"title": "Elastic Defend",
|
"title": "Elastic Defend",
|
||||||
"version": "9.3.0",
|
"version": "9.3.1",
|
||||||
"requires_root": true
|
"requires_root": true
|
||||||
},
|
},
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"\\.gz$"
|
"\\.gz$"
|
||||||
],
|
],
|
||||||
"include_files": [],
|
"include_files": [],
|
||||||
"processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.15.0\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.8.0\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.15.0\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.15.0\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.8.0\n- add_fields:\n target: data_stream\n fields:\n dataset: import",
|
"processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.20.0\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.8.3\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.20.0\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.20.0\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.8.3\n- add_fields:\n target: data_stream\n fields:\n dataset: import",
|
||||||
"tags": [
|
"tags": [
|
||||||
"import"
|
"import"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
{% set AGENT_STATUS = salt['service.available']('elastic-agent') %}
|
{% set AGENT_STATUS = salt['service.available']('elastic-agent') %}
|
||||||
{% set AGENT_EXISTS = salt['file.file_exists']('/opt/Elastic/Agent/elastic-agent') %}
|
{% set AGENT_EXISTS = salt['file.file_exists']('/opt/Elastic/Agent/elastic-agent') %}
|
||||||
|
|
||||||
|
so-elastic-agent-install:
|
||||||
|
file.managed:
|
||||||
|
- name: /usr/sbin/so-elastic-agent-install
|
||||||
|
- source: salt://elasticfleet/tools/sbin/so-elastic-agent-install
|
||||||
|
- user: 947
|
||||||
|
- group: 939
|
||||||
|
- mode: 755
|
||||||
|
- show_changes: False
|
||||||
|
|
||||||
{% if not AGENT_STATUS or not AGENT_EXISTS %}
|
{% if not AGENT_STATUS or not AGENT_EXISTS %}
|
||||||
|
|
||||||
pull_agent_installer:
|
pull_agent_installer:
|
||||||
@@ -21,11 +30,9 @@ pull_agent_installer:
|
|||||||
|
|
||||||
run_installer:
|
run_installer:
|
||||||
cmd.run:
|
cmd.run:
|
||||||
- name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }} -force
|
- name: /usr/sbin/so-elastic-agent-install "{{ GRIDNODETOKEN }}"
|
||||||
- cwd: /opt/so
|
- require:
|
||||||
- retry:
|
- file: pull_agent_installer
|
||||||
attempts: 3
|
|
||||||
interval: 20
|
|
||||||
|
|
||||||
cleanup_agent_installer:
|
cleanup_agent_installer:
|
||||||
file.absent:
|
file.absent:
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#!/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-elastic-fleet-common
|
||||||
|
|
||||||
|
|
||||||
|
# passed in as arg from elasticfleet/install_agent_grid.sls, else pulled from pillar later
|
||||||
|
GRIDNODETOKEN="$1"
|
||||||
|
LOGFILE="/opt/so/SO-Elastic-Agent_Installer_Health.log"
|
||||||
|
|
||||||
|
check_agent_health() {
|
||||||
|
timeout=300
|
||||||
|
interval=10
|
||||||
|
start=$SECONDS
|
||||||
|
|
||||||
|
while (( SECONDS - start < timeout )); do
|
||||||
|
agent_status=$(elastic-agent status 2>&1)
|
||||||
|
echo -e "\n$(date)\n$agent_status\n" >> "$LOGFILE"
|
||||||
|
if echo "$agent_status" | grep -A1 'elastic-agent$' | grep -q 'status: (HEALTHY)'; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "The Elastic Agent is not yet healthy. Waiting for ${interval} seconds before checking again..."
|
||||||
|
sleep "$interval"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "The Elastic Agent did not become healthy within ${timeout} seconds"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall_agent() {
|
||||||
|
if command -v elastic-agent >/dev/null 2>&1; then
|
||||||
|
elastic-agent uninstall -f
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "$GRIDNODETOKEN" ]]; then
|
||||||
|
noderole=$(so-yaml.py get -r /etc/salt/grains role)
|
||||||
|
if [[ "$noderole" == "so-heavynode" ]]; then
|
||||||
|
GRIDNODETOKEN=$(salt-call pillar.get global:fleet_grid_enrollment_token_heavy --out=newline_values_only)
|
||||||
|
else
|
||||||
|
GRIDNODETOKEN=$(salt-call pillar.get global:fleet_grid_enrollment_token_general --out=newline_values_only)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$GRIDNODETOKEN" ]]; then
|
||||||
|
echo "Unable to determine Elastic Fleet enrollment token. Exiting."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -x /opt/so/so-elastic-agent_linux_amd64 ]]; then
|
||||||
|
echo "Downloading so-elastic-agent installer... This could take a while if another Salt job is running."
|
||||||
|
|
||||||
|
# When running outside of elasticfleet/install_agent_grid.sls we need to download the installer independently.
|
||||||
|
# PYTHONWARNINGS="ignore" to avoid messages like the following when running salt-call:
|
||||||
|
# '/opt/saltstack/salt/lib/python3.10/site-packages/salt/transport/base.py:129: TransportWarning: Unclosed transport! <salt.transport.zeromq.RequestClient object at 0x7fc5f0ee7a30>
|
||||||
|
# File "/bin/salt-call", line 12, in <module>
|
||||||
|
# sys.exit(salt_call())'
|
||||||
|
|
||||||
|
PYTHONWARNINGS="ignore" salt-call state.single file.managed name=/opt/so/so-elastic-agent_linux_amd64 source=salt://elasticfleet/files/so_agent-installers/so-elastic-agent_linux_amd64 mode=755 makedirs=True queue=True
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -x /opt/so/so-elastic-agent_linux_amd64 ]]; then
|
||||||
|
attempts=0
|
||||||
|
cd /opt/so/ || exit 1
|
||||||
|
|
||||||
|
truncate -s 0 "$LOGFILE"
|
||||||
|
|
||||||
|
uninstall_agent
|
||||||
|
|
||||||
|
while [[ $attempts -lt 3 ]]; do
|
||||||
|
if ./so-elastic-agent_linux_amd64 -token="$GRIDNODETOKEN" -force && echo "Verifying Elastic Agent health..." && check_agent_health; then
|
||||||
|
rm -f /opt/so/so-elastic-agent_linux_amd64
|
||||||
|
elastic-agent status
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
|
||||||
|
if [[ $attempts -lt 3 ]]; then
|
||||||
|
echo "Unable to verify Elastic Agent health... Retrying in 20 seconds..."
|
||||||
|
sleep 20
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
uninstall_agent
|
||||||
|
rm -f /opt/so/so-elastic-agent_linux_amd64
|
||||||
|
echo "The so-elastic-agent installer failed after 3 attempts. Exiting."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Unable to locate so-elastic-agent installer. Exiting."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -30,7 +30,7 @@ done
|
|||||||
if [[ -z $FLEETHOST ]] || [[ -z $ENROLLMENTOKEN ]]; then
|
if [[ -z $FLEETHOST ]] || [[ -z $ENROLLMENTOKEN ]]; then
|
||||||
printf "\nFleet Host URL, Enrollment Token or Elastic Version empty - exiting..."
|
printf "\nFleet Host URL, Enrollment Token or Elastic Version empty - exiting..."
|
||||||
printf "\nFleet Host: $FLEETHOST, Enrollment Token: $ENROLLMENTOKEN\n"
|
printf "\nFleet Host: $FLEETHOST, Enrollment Token: $ENROLLMENTOKEN\n"
|
||||||
exit
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OSARCH=( "linux-x86_64" "windows-x86_64" "darwin-x86_64" "darwin-aarch64" )
|
OSARCH=( "linux-x86_64" "windows-x86_64" "darwin-x86_64" "darwin-aarch64" )
|
||||||
@@ -62,31 +62,54 @@ do
|
|||||||
done
|
done
|
||||||
|
|
||||||
GOTARGETOS=( "linux" "windows" "darwin" "darwin/arm64" )
|
GOTARGETOS=( "linux" "windows" "darwin" "darwin/arm64" )
|
||||||
GOARCH="amd64"
|
|
||||||
printf "\n### Generating OS packages using the cleaned up tarballs"
|
printf "\n### Generating OS packages using the cleaned up tarballs"
|
||||||
for GOOS in "${GOTARGETOS[@]}"
|
for GOOS in "${GOTARGETOS[@]}"; do
|
||||||
do
|
GOARCH="amd64"
|
||||||
if [[ $GOOS == 'darwin/arm64' ]]; then GOOS="darwin" && GOARCH="arm64"; fi
|
if [[ $GOOS == 'darwin/arm64' ]]; then GOOS="darwin" && GOARCH="arm64"; fi
|
||||||
printf "\n\n### Generating $GOOS/$GOARCH Installer...\n"
|
printf "\n\n### Generating $GOOS/$GOARCH Installer...\n"
|
||||||
docker run -e CGO_ENABLED=0 -e GOOS=$GOOS -e GOARCH=$GOARCH \
|
docker run -e CGO_ENABLED=0 -e GOOS=$GOOS -e GOARCH=$GOARCH \
|
||||||
--mount type=bind,source=/etc/pki/tls/certs/,target=/workspace/files/cert/ \
|
--mount type=bind,source=/etc/pki/tls/certs/,target=/workspace/files/cert/ \
|
||||||
--mount type=bind,source=/nsm/elastic-agent-workspace/,target=/workspace/files/elastic-agent/ \
|
--mount type=bind,source=/nsm/elastic-agent-workspace/,target=/workspace/files/elastic-agent/ \
|
||||||
--mount type=bind,source=/opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/,target=/output/ \
|
--mount type=bind,source=/opt/so/saltstack/local/salt/elasticfleet/files/,target=/output/ \
|
||||||
{{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent-builder:{{ GLOBALS.so_version }} go build -ldflags "-X main.fleetHostURLsList=$FLEETHOST -X main.enrollmentToken=$ENROLLMENTOKEN" -o /output/so-elastic-agent_${GOOS}_${GOARCH}
|
{{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent-builder:{{ GLOBALS.so_version }} go build -ldflags "-X main.fleetHostURLsList=$FLEETHOST -X main.enrollmentToken=$ENROLLMENTOKEN" -o /output/so-elastic-agent_${GOOS}_${GOARCH}
|
||||||
printf "\n### $GOOS/$GOARCH Installer Generated...\n"
|
printf "\n### $GOOS/$GOARCH Installer Generated...\n"
|
||||||
done
|
done
|
||||||
|
|
||||||
printf "\n\n### Generating MSI...\n"
|
printf "\n\n### Generating MSI...\n"
|
||||||
cp /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/so-elastic-agent_windows_amd64 /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/so-elastic-agent_windows_amd64.exe
|
cp /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_windows_amd64 /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_windows_amd64.exe
|
||||||
docker run \
|
docker run \
|
||||||
--mount type=bind,source=/opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/,target=/output/ -w /output \
|
--mount type=bind,source=/opt/so/saltstack/local/salt/elasticfleet/files/,target=/output/ -w /output \
|
||||||
{{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent-builder:{{ GLOBALS.so_version }} wixl -o so-elastic-agent_windows_amd64_msi --arch x64 /workspace/so-elastic-agent.wxs
|
{{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent-builder:{{ GLOBALS.so_version }} wixl -o so-elastic-agent_windows_amd64_msi --arch x64 /workspace/so-elastic-agent.wxs
|
||||||
printf "\n### MSI Generated...\n"
|
printf "\n### MSI Generated...\n"
|
||||||
|
|
||||||
|
# Verify installers were created
|
||||||
|
for GOOS in "${GOTARGETOS[@]}"; do
|
||||||
|
GOARCH="amd64"
|
||||||
|
if [[ $GOOS == 'darwin/arm64' ]]; then GOOS="darwin"; GOARCH="arm64"; fi
|
||||||
|
if [[ ! -f /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_${GOOS}_${GOARCH} ]]; then
|
||||||
|
printf "\n### ERROR: Installer for %s/%s was not generated. Exiting...\n" "$GOOS" "$GOARCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# After verifying new installer was generated, move it to so_agent-installers directory
|
||||||
|
mv /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_${GOOS}_${GOARCH} /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/
|
||||||
|
done
|
||||||
|
|
||||||
|
# Verify MSI installer
|
||||||
|
if [[ ! -f /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_windows_amd64_msi ]]; then
|
||||||
|
printf "\n### ERROR: Installer MSI was not generated. Exiting...\n"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
# After verifying new installer MSI was generated, move it to so_agent-installers directory
|
||||||
|
mv /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_windows_amd64_msi /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/
|
||||||
|
fi
|
||||||
|
|
||||||
printf "\n### Cleaning up temp files \n"
|
printf "\n### Cleaning up temp files \n"
|
||||||
rm -rf /nsm/elastic-agent-workspace
|
rm -rf /nsm/elastic-agent-workspace
|
||||||
rm -rf /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/so-elastic-agent_windows_amd64.exe
|
rm -rf /opt/so/saltstack/local/salt/elasticfleet/files/so-elastic-agent_windows_amd64.exe
|
||||||
|
|
||||||
printf "\n### Copying so_agent-installers to /nsm/elastic-fleet/ for nginx.\n"
|
printf "\n### Copying so_agent-installers to /nsm/elastic-fleet/ for nginx.\n"
|
||||||
\cp -vr /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/ /nsm/elastic-fleet/
|
\cp -vr /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/ /nsm/elastic-fleet/
|
||||||
chmod 644 /nsm/elastic-fleet/so_agent-installers/*
|
chmod 644 /nsm/elastic-fleet/so_agent-installers/*
|
||||||
|
|
||||||
|
# if we got here all installers have been generated successfully
|
||||||
|
exit 0
|
||||||
|
|||||||
@@ -244,11 +244,37 @@ printf '%s\n'\
|
|||||||
"" >> "$global_pillar_file"
|
"" >> "$global_pillar_file"
|
||||||
|
|
||||||
# Call Elastic-Fleet Salt State
|
# Call Elastic-Fleet Salt State
|
||||||
printf "\nApplying elasticfleet state"
|
printf "\nApplying elasticfleet state\n"
|
||||||
salt-call state.apply elasticfleet queue=True
|
for state_attempt in {1..3}; do
|
||||||
|
if salt-call state.apply elasticfleet queue=True; then
|
||||||
|
break
|
||||||
|
elif [[ $state_attempt -lt 3 ]]; then
|
||||||
|
printf "\nElasticfleet state did not complete successfully... Attempt (%s/3). Retrying...\n" "$state_attempt"
|
||||||
|
sleep 10
|
||||||
|
else
|
||||||
|
printf "\nFailure(s) in elasticfleet state... Exiting...\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\nRunning so-elastic-agent-gen-installers\n"
|
||||||
# Generate installers & install Elastic Agent on the node
|
# Generate installers & install Elastic Agent on the node
|
||||||
so-elastic-agent-gen-installers
|
for agent_gen_attempt in {1..3}; do
|
||||||
printf "\nApplying elasticfleet.install_agent_grid state"
|
if so-elastic-agent-gen-installers; then
|
||||||
salt-call state.apply elasticfleet.install_agent_grid queue=True
|
break
|
||||||
exit 0
|
elif [[ $agent_gen_attempt -lt 3 ]]; then
|
||||||
|
printf "\nUnable to generate Elastic Agent installers... Attempt (%s/3). Retrying...\n" "$agent_gen_attempt"
|
||||||
|
sleep 10
|
||||||
|
else
|
||||||
|
printf "\nFailed to generate Elastic Agent installers after 3 attempts. Exiting...\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\nApplying elasticfleet.install_agent_grid state\n"
|
||||||
|
if ! salt-call state.apply elasticfleet.install_agent_grid queue=True; then
|
||||||
|
printf "\nFailure(s) in elasticfleet.install_agent_grid state... Exiting...\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\nElastic Fleet setup completed successfully\n"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
enabled: false
|
enabled: false
|
||||||
version: 9.3.3
|
version: 9.3.7
|
||||||
index_clean: true
|
index_clean: true
|
||||||
data_retention_method: DLM
|
data_retention_method: DLM
|
||||||
vm:
|
vm:
|
||||||
|
|||||||
+10
-10
@@ -118,70 +118,70 @@
|
|||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_e16851a7",
|
"tag": "pipeline_e16851a7",
|
||||||
"name": "logs-pfsense.log-1.25.2-firewall",
|
"name": "logs-pfsense.log-1.25.4-firewall",
|
||||||
"if": "ctx.event.provider == 'filterlog'"
|
"if": "ctx.event.provider == 'filterlog'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_828590b5",
|
"tag": "pipeline_828590b5",
|
||||||
"name": "logs-pfsense.log-1.25.2-openvpn",
|
"name": "logs-pfsense.log-1.25.4-openvpn",
|
||||||
"if": "ctx.event.provider == 'openvpn'"
|
"if": "ctx.event.provider == 'openvpn'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_9d37039c",
|
"tag": "pipeline_9d37039c",
|
||||||
"name": "logs-pfsense.log-1.25.2-ipsec",
|
"name": "logs-pfsense.log-1.25.4-ipsec",
|
||||||
"if": "ctx.event.provider == 'charon'"
|
"if": "ctx.event.provider == 'charon'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_ad56bbca",
|
"tag": "pipeline_ad56bbca",
|
||||||
"name": "logs-pfsense.log-1.25.2-dhcp",
|
"name": "logs-pfsense.log-1.25.4-dhcp",
|
||||||
"if": "[\"dhcpd\", \"dhclient\", \"dhcp6c\", \"dnsmasq-dhcp\"].contains(ctx.event.provider)"
|
"if": "[\"dhcpd\", \"dhclient\", \"dhcp6c\", \"dnsmasq-dhcp\"].contains(ctx.event.provider)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_dd85553d",
|
"tag": "pipeline_dd85553d",
|
||||||
"name": "logs-pfsense.log-1.25.2-unbound",
|
"name": "logs-pfsense.log-1.25.4-unbound",
|
||||||
"if": "ctx.event.provider == 'unbound'"
|
"if": "ctx.event.provider == 'unbound'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_720ed255",
|
"tag": "pipeline_720ed255",
|
||||||
"name": "logs-pfsense.log-1.25.2-haproxy",
|
"name": "logs-pfsense.log-1.25.4-haproxy",
|
||||||
"if": "ctx.event.provider == 'haproxy'"
|
"if": "ctx.event.provider == 'haproxy'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_456beba5",
|
"tag": "pipeline_456beba5",
|
||||||
"name": "logs-pfsense.log-1.25.2-php-fpm",
|
"name": "logs-pfsense.log-1.25.4-php-fpm",
|
||||||
"if": "ctx.event.provider == 'php-fpm'"
|
"if": "ctx.event.provider == 'php-fpm'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_a0d89375",
|
"tag": "pipeline_a0d89375",
|
||||||
"name": "logs-pfsense.log-1.25.2-squid",
|
"name": "logs-pfsense.log-1.25.4-squid",
|
||||||
"if": "ctx.event.provider == 'squid'"
|
"if": "ctx.event.provider == 'squid'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag": "pipeline_c2f1ed55",
|
"tag": "pipeline_c2f1ed55",
|
||||||
"name": "logs-pfsense.log-1.25.2-snort",
|
"name": "logs-pfsense.log-1.25.4-snort",
|
||||||
"if": "ctx.event.provider == 'snort'"
|
"if": "ctx.event.provider == 'snort'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"tag":"pipeline_33db1c9e",
|
"tag":"pipeline_33db1c9e",
|
||||||
"name": "logs-pfsense.log-1.25.2-suricata",
|
"name": "logs-pfsense.log-1.25.4-suricata",
|
||||||
"if": "ctx.event.provider == 'suricata'"
|
"if": "ctx.event.provider == 'suricata'"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -645,6 +645,7 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch
|
helpLink: elasticsearch
|
||||||
|
so-logs-soc: *dataStreamSettings
|
||||||
so-logs-system_x_auth: *dataStreamSettings
|
so-logs-system_x_auth: *dataStreamSettings
|
||||||
so-logs-system_x_syslog: *dataStreamSettings
|
so-logs-system_x_syslog: *dataStreamSettings
|
||||||
so-logs-system_x_system: *dataStreamSettings
|
so-logs-system_x_system: *dataStreamSettings
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ kibana:
|
|||||||
- default
|
- default
|
||||||
- file
|
- file
|
||||||
migrations:
|
migrations:
|
||||||
discardCorruptObjects: "9.3.3"
|
discardCorruptObjects: "9.3.7"
|
||||||
telemetry:
|
telemetry:
|
||||||
enabled: False
|
enabled: False
|
||||||
xpack:
|
xpack:
|
||||||
|
|||||||
+122
-10
@@ -12,7 +12,17 @@
|
|||||||
UPDATE_DIR=/tmp/sogh/securityonion
|
UPDATE_DIR=/tmp/sogh/securityonion
|
||||||
DEFAULT_SALT_DIR=/opt/so/saltstack/default
|
DEFAULT_SALT_DIR=/opt/so/saltstack/default
|
||||||
INSTALLEDVERSION=$(cat /etc/soversion)
|
INSTALLEDVERSION=$(cat /etc/soversion)
|
||||||
POSTVERSION=$INSTALLEDVERSION
|
# /etc/sopostversion is a soup-owned marker (no salt state manages it) tracking how
|
||||||
|
# far the post-upgrade walk has progressed. Its presence means a prior upgrade did
|
||||||
|
# not finish its post-upgrade steps; its contents are the resume point. It is read
|
||||||
|
# here before preupgrade_changes mutates INSTALLEDVERSION and before any highstate
|
||||||
|
# stamps /etc/soversion from the pillar.
|
||||||
|
POSTVERSION_FILE=/etc/sopostversion
|
||||||
|
if [ -f "$POSTVERSION_FILE" ]; then
|
||||||
|
POSTVERSION=$(cat "$POSTVERSION_FILE")
|
||||||
|
else
|
||||||
|
POSTVERSION=$INSTALLEDVERSION
|
||||||
|
fi
|
||||||
INSTALLEDSALTVERSION=$(salt --versions-report | grep Salt: | awk '{print $2}')
|
INSTALLEDSALTVERSION=$(salt --versions-report | grep Salt: | awk '{print $2}')
|
||||||
BATCHSIZE=5
|
BATCHSIZE=5
|
||||||
SOUP_LOG=/root/soup.log
|
SOUP_LOG=/root/soup.log
|
||||||
@@ -23,6 +33,10 @@ 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
|
SALTUPGRADED=false
|
||||||
|
# Set true once soup begins modifying the system (past the pre-flight checks), so the
|
||||||
|
# EXIT trap can tell the user the update did not finish and must be re-run. Only the
|
||||||
|
# pre-flight gates (ES compatibility, disk, network) fail before this is set.
|
||||||
|
SOUP_UPGRADE_STARTED=false
|
||||||
SALT_CLOUD_INSTALLED=false
|
SALT_CLOUD_INSTALLED=false
|
||||||
SALT_CLOUD_CONFIGURED=false
|
SALT_CLOUD_CONFIGURED=false
|
||||||
# Check if salt-cloud is installed
|
# Check if salt-cloud is installed
|
||||||
@@ -123,6 +137,28 @@ check_err() {
|
|||||||
|
|
||||||
echo "SOUP XTRACE debug log (if enabled) at $SOUP_DEBUG_LOG. Re-run soup with SOUP_DEBUG=1 to create $SOUP_DEBUG_LOG"
|
echo "SOUP XTRACE debug log (if enabled) at $SOUP_DEBUG_LOG. Re-run soup with SOUP_DEBUG=1 to create $SOUP_DEBUG_LOG"
|
||||||
|
|
||||||
|
# If soup had already started modifying the system, make it unmistakable that the
|
||||||
|
# update is incomplete and must be re-run. soup is resumable: a version upgrade
|
||||||
|
# picks up from the /etc/sopostversion marker, and a hotfix re-applies because
|
||||||
|
# /etc/sohotfix is only advanced after a successful highstate.
|
||||||
|
if [[ "$SOUP_UPGRADE_STARTED" == "true" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "=============================================================================="
|
||||||
|
echo " UPGRADE INCOMPLETE"
|
||||||
|
echo "=============================================================================="
|
||||||
|
echo " This soup run did NOT finish. Your Security Onion installation may be in a"
|
||||||
|
echo " partially-updated state and is not yet fully upgraded."
|
||||||
|
echo ""
|
||||||
|
echo " Review the error above and $SOUP_LOG, resolve the underlying problem, then"
|
||||||
|
echo " run soup again to resume and complete the update:"
|
||||||
|
echo ""
|
||||||
|
echo " sudo soup"
|
||||||
|
echo ""
|
||||||
|
echo " soup is resumable -- re-running it continues from where this run stopped."
|
||||||
|
echo "=============================================================================="
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
exit $exit_code
|
exit $exit_code
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -291,6 +327,30 @@ check_pillar_items() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_cluster_health() {
|
||||||
|
echo "Checking Elasticsearch cluster health."
|
||||||
|
# Require a 'green' cluster before upgrading; anything less (yellow, red, or
|
||||||
|
# unreachable) blocks. Modeled on the wait used in so-elasticsearch-roles-load.
|
||||||
|
if so-elasticsearch-query "_cluster/health?wait_for_status=green&timeout=120s" --fail > /dev/null 2>&1; then
|
||||||
|
printf "\nThe Elasticsearch cluster is healthy (green). We can proceed with SOUP.\n\n"
|
||||||
|
else
|
||||||
|
printf "\nThe Elasticsearch cluster is not green. Please resolve the cluster health issue so the cluster is green before running SOUP again.\n\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_fleet_server() {
|
||||||
|
echo "Checking that Elastic Fleet Server is responding."
|
||||||
|
# Modeled on the wait_for_so-elastic-fleet state check in elasticfleet/enabled.sls,
|
||||||
|
# which waits for HTTP 200 from the Fleet Server status API.
|
||||||
|
if curl -sk --fail --retry 3 --retry-delay 10 --max-time 30 "https://localhost:8220/api/status" > /dev/null 2>&1; then
|
||||||
|
printf "\nElastic Fleet Server is responding. We can proceed with SOUP.\n\n"
|
||||||
|
else
|
||||||
|
printf "\nElastic Fleet Server is not responding at https://localhost:8220/api/status. Please ensure Elastic Fleet is healthy before running SOUP again.\n\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
check_saltmaster_status() {
|
check_saltmaster_status() {
|
||||||
set +e
|
set +e
|
||||||
echo "Waiting on the Salt Master service to be ready."
|
echo "Waiting on the Salt Master service to be ready."
|
||||||
@@ -377,6 +437,8 @@ get_soup_script_hashes() {
|
|||||||
GITIMGCMN=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/so-image-common | awk '{print $1}')
|
GITIMGCMN=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/so-image-common | awk '{print $1}')
|
||||||
CURRENTSOFIREWALL=$(md5sum /usr/sbin/so-firewall | awk '{print $1}')
|
CURRENTSOFIREWALL=$(md5sum /usr/sbin/so-firewall | awk '{print $1}')
|
||||||
GITSOFIREWALL=$(md5sum $UPDATE_DIR/salt/manager/tools/sbin/so-firewall | awk '{print $1}')
|
GITSOFIREWALL=$(md5sum $UPDATE_DIR/salt/manager/tools/sbin/so-firewall | awk '{print $1}')
|
||||||
|
CURRENTSOYAML=$(md5sum /usr/sbin/so-yaml.py | awk '{print $1}')
|
||||||
|
GITSOYAML=$(md5sum $UPDATE_DIR/salt/manager/tools/sbin/so-yaml.py | awk '{print $1}')
|
||||||
}
|
}
|
||||||
|
|
||||||
highstate() {
|
highstate() {
|
||||||
@@ -414,6 +476,13 @@ preupgrade_changes() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_postversion() {
|
||||||
|
# Persist post-upgrade walk progress so an interrupted upgrade can resume the
|
||||||
|
# remaining steps on the next soup run (see /etc/sopostversion handling).
|
||||||
|
POSTVERSION="$1"
|
||||||
|
echo "$POSTVERSION" > "$POSTVERSION_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
postupgrade_changes() {
|
postupgrade_changes() {
|
||||||
# This function is to add any new pillar items if needed.
|
# This function is to add any new pillar items if needed.
|
||||||
echo "Running post upgrade processes."
|
echo "Running post upgrade processes."
|
||||||
@@ -421,6 +490,8 @@ postupgrade_changes() {
|
|||||||
[[ "$POSTVERSION" =~ ^2\.4\.21[0-9]+$ ]] && post_to_3.0.0
|
[[ "$POSTVERSION" =~ ^2\.4\.21[0-9]+$ ]] && post_to_3.0.0
|
||||||
[[ "$POSTVERSION" == "3.0.0" ]] && post_to_3.1.0
|
[[ "$POSTVERSION" == "3.0.0" ]] && post_to_3.1.0
|
||||||
[[ "$POSTVERSION" == "3.1.0" ]] && post_to_3.2.0
|
[[ "$POSTVERSION" == "3.1.0" ]] && post_to_3.2.0
|
||||||
|
# All applicable post-upgrade steps completed; clear the resume marker.
|
||||||
|
rm -f "$POSTVERSION_FILE"
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,7 +584,7 @@ post_to_3.0.0() {
|
|||||||
# convert yes/no in suricata pillars to true/false
|
# convert yes/no in suricata pillars to true/false
|
||||||
convert_suricata_yes_no
|
convert_suricata_yes_no
|
||||||
|
|
||||||
POSTVERSION=3.0.0
|
set_postversion 3.0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
### 3.0.0 End ###
|
### 3.0.0 End ###
|
||||||
@@ -740,7 +811,6 @@ fix_logstash_0013_lumberjack_pipeline_name() {
|
|||||||
up_to_3.1.0() {
|
up_to_3.1.0() {
|
||||||
ensure_postgres_local_pillar
|
ensure_postgres_local_pillar
|
||||||
ensure_postgres_secret
|
ensure_postgres_secret
|
||||||
determine_elastic_agent_upgrade
|
|
||||||
elasticsearch_backup_index_templates
|
elasticsearch_backup_index_templates
|
||||||
# Clear existing component template state file.
|
# Clear existing component template state file.
|
||||||
rm -f /opt/so/state/esfleet_component_templates.json
|
rm -f /opt/so/state/esfleet_component_templates.json
|
||||||
@@ -777,7 +847,7 @@ post_to_3.1.0() {
|
|||||||
# Check for unhealthy / unauthorized integration transform jobs and attempt reauthorizations
|
# Check for unhealthy / unauthorized integration transform jobs and attempt reauthorizations
|
||||||
check_transform_health_and_reauthorize || true
|
check_transform_health_and_reauthorize || true
|
||||||
|
|
||||||
POSTVERSION=3.1.0
|
set_postversion 3.1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
### 3.1.0 End ###
|
### 3.1.0 End ###
|
||||||
@@ -888,6 +958,9 @@ update_kafka_metadata() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
up_to_3.2.0() {
|
up_to_3.2.0() {
|
||||||
|
# download 9.3.7 elastic agent packages
|
||||||
|
determine_elastic_agent_upgrade
|
||||||
|
|
||||||
fix_logstash_0013_lumberjack_pipeline_name
|
fix_logstash_0013_lumberjack_pipeline_name
|
||||||
|
|
||||||
pin_elasticsearch_data_retention_method
|
pin_elasticsearch_data_retention_method
|
||||||
@@ -901,7 +974,7 @@ post_to_3.2.0() {
|
|||||||
|
|
||||||
bootstrap_so_soc_database
|
bootstrap_so_soc_database
|
||||||
|
|
||||||
# Including agent regen script here since it was missed in post_to_3.1.0
|
# Generate 9.3.7 elastic agent installers
|
||||||
echo "Regenerating Elastic Agent Installers"
|
echo "Regenerating Elastic Agent Installers"
|
||||||
/sbin/so-elastic-agent-gen-installers
|
/sbin/so-elastic-agent-gen-installers
|
||||||
|
|
||||||
@@ -909,7 +982,7 @@ post_to_3.2.0() {
|
|||||||
|
|
||||||
update_kafka_metadata "4.3"
|
update_kafka_metadata "4.3"
|
||||||
|
|
||||||
POSTVERSION=3.2.0
|
set_postversion 3.2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
### 3.2.0 End ###
|
### 3.2.0 End ###
|
||||||
@@ -1061,8 +1134,20 @@ upgrade_check() {
|
|||||||
fi
|
fi
|
||||||
[[ -f /etc/sohotfix ]] && CURRENTHOTFIX=$(cat /etc/sohotfix)
|
[[ -f /etc/sohotfix ]] && CURRENTHOTFIX=$(cat /etc/sohotfix)
|
||||||
if [ "$INSTALLEDVERSION" == "$NEWVERSION" ]; then
|
if [ "$INSTALLEDVERSION" == "$NEWVERSION" ]; then
|
||||||
|
# A leftover post-version marker means a previous upgrade to this version
|
||||||
|
# advanced /etc/soversion (the highstate stamps it from the pillar) but did not
|
||||||
|
# finish its post-upgrade steps. Resume the upgrade instead of reporting "latest".
|
||||||
|
if [ -f "$POSTVERSION_FILE" ] && [ "$(cat "$POSTVERSION_FILE")" != "$NEWVERSION" ]; then
|
||||||
|
echo "A previous upgrade to $NEWVERSION did not complete its post-upgrade steps; resuming."
|
||||||
|
is_hotfix=false
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
echo "Checking to see if there are hotfixes needed"
|
echo "Checking to see if there are hotfixes needed"
|
||||||
if [ "$HOTFIXVERSION" == "$CURRENTHOTFIX" ]; then
|
if [ "$HOTFIXVERSION" == "$CURRENTHOTFIX" ]; then
|
||||||
|
# Reaching here means we are at the target version and NOT resuming (the resume
|
||||||
|
# check above returned otherwise). Clear any stale resume marker so a completed
|
||||||
|
# upgrade is never mistaken for a partial one and re-run on a later invocation.
|
||||||
|
rm -f "$POSTVERSION_FILE"
|
||||||
echo "You are already running the latest version of Security Onion."
|
echo "You are already running the latest version of Security Onion."
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
@@ -1141,7 +1226,7 @@ upgrade_salt() {
|
|||||||
|
|
||||||
verify_latest_update_script() {
|
verify_latest_update_script() {
|
||||||
get_soup_script_hashes
|
get_soup_script_hashes
|
||||||
if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" && "$CURRENTSOFIREWALL" == "$GITSOFIREWALL" ]]; then
|
if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" && "$CURRENTSOFIREWALL" == "$GITSOFIREWALL" && "$CURRENTSOYAML" == "$GITSOYAML" ]]; then
|
||||||
echo "This version of the soup script is up to date. Proceeding."
|
echo "This version of the soup script is up to date. Proceeding."
|
||||||
else
|
else
|
||||||
echo "You are not running the latest soup version. Updating soup and its components. This might take multiple runs to complete."
|
echo "You are not running the latest soup version. Updating soup and its components. This might take multiple runs to complete."
|
||||||
@@ -1150,7 +1235,7 @@ verify_latest_update_script() {
|
|||||||
|
|
||||||
# Verify that soup scripts updated as expected
|
# Verify that soup scripts updated as expected
|
||||||
get_soup_script_hashes
|
get_soup_script_hashes
|
||||||
if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" && "$CURRENTSOFIREWALL" == "$GITSOFIREWALL" ]]; then
|
if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" && "$CURRENTSOFIREWALL" == "$GITSOFIREWALL" && "$CURRENTSOYAML" == "$GITSOYAML" ]]; then
|
||||||
echo "Succesfully updated soup scripts."
|
echo "Succesfully updated soup scripts."
|
||||||
else
|
else
|
||||||
echo "There was a problem updating soup scripts. Trying to rerun script update."
|
echo "There was a problem updating soup scripts. Trying to rerun script update."
|
||||||
@@ -1174,7 +1259,8 @@ verify_es_version_compatibility() {
|
|||||||
["8.18.4"]="8.18.6 8.18.8 9.0.8"
|
["8.18.4"]="8.18.6 8.18.8 9.0.8"
|
||||||
["8.18.6"]="8.18.8 9.0.8"
|
["8.18.6"]="8.18.8 9.0.8"
|
||||||
["8.18.8"]="9.0.8"
|
["8.18.8"]="9.0.8"
|
||||||
["9.0.8"]="9.3.3"
|
["9.0.8"]="9.3.3 9.3.7"
|
||||||
|
["9.3.3"]="9.3.7"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Elasticsearch MUST upgrade through these versions
|
# Elasticsearch MUST upgrade through these versions
|
||||||
@@ -1757,6 +1843,15 @@ main() {
|
|||||||
set_minionid
|
set_minionid
|
||||||
MINION_ROLE=$(lookup_role)
|
MINION_ROLE=$(lookup_role)
|
||||||
echo "Found that Security Onion $INSTALLEDVERSION is currently installed."
|
echo "Found that Security Onion $INSTALLEDVERSION is currently installed."
|
||||||
|
# /etc/soversion is stamped to the target version before the upgrade fully
|
||||||
|
# completes, so a lingering resume marker means this grid is only partially
|
||||||
|
# upgraded even though the line above shows the target version. Make that explicit
|
||||||
|
# so it is not mistaken for a finished upgrade.
|
||||||
|
if [ -f "$POSTVERSION_FILE" ] && [ "$(cat "$POSTVERSION_FILE")" != "$INSTALLEDVERSION" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "NOTE: A previous upgrade to $INSTALLEDVERSION did not finish. This grid is"
|
||||||
|
echo " partially upgraded and this soup run will resume and complete it."
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
check_minimum_version
|
check_minimum_version
|
||||||
|
|
||||||
@@ -1785,6 +1880,12 @@ main() {
|
|||||||
echo "Verifying Elasticsearch version compatibility across the grid before upgrading."
|
echo "Verifying Elasticsearch version compatibility across the grid before upgrading."
|
||||||
verify_es_version_compatibility
|
verify_es_version_compatibility
|
||||||
|
|
||||||
|
# Pre-flight health checks: confirm the grid is in a good state before we change
|
||||||
|
# anything. These run before any modifications, so a failure exits cleanly and the
|
||||||
|
# operator can fix the issue and re-run soup.
|
||||||
|
check_cluster_health
|
||||||
|
check_fleet_server
|
||||||
|
|
||||||
echo "Checking for Salt Master and Minion updates."
|
echo "Checking for Salt Master and Minion updates."
|
||||||
upgrade_check_salt
|
upgrade_check_salt
|
||||||
set -e
|
set -e
|
||||||
@@ -1801,6 +1902,7 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$is_hotfix" == "true" ]; then
|
if [ "$is_hotfix" == "true" ]; then
|
||||||
|
SOUP_UPGRADE_STARTED=true
|
||||||
echo "Applying $HOTFIXVERSION hotfix"
|
echo "Applying $HOTFIXVERSION hotfix"
|
||||||
# since we don't run the backup.config_backup state on import we wont snapshot previous version states and pillars
|
# since we don't run the backup.config_backup state on import we wont snapshot previous version states and pillars
|
||||||
if [[ ! "$MINION_ROLE" == "import" ]]; then
|
if [[ ! "$MINION_ROLE" == "import" ]]; then
|
||||||
@@ -1811,10 +1913,16 @@ main() {
|
|||||||
create_local_directories "/opt/so/saltstack/default"
|
create_local_directories "/opt/so/saltstack/default"
|
||||||
apply_hotfix
|
apply_hotfix
|
||||||
echo "Hotfix applied"
|
echo "Hotfix applied"
|
||||||
update_version
|
|
||||||
enable_highstate
|
enable_highstate
|
||||||
highstate
|
highstate
|
||||||
|
# Record the hotfix only after the highstate succeeds. /etc/sohotfix is written
|
||||||
|
# solely by soup (no salt state manages it), so deferring the write means a failed
|
||||||
|
# hotfix highstate leaves the old hotfix value and re-running soup re-applies it,
|
||||||
|
# rather than reporting "already latest". The soversion/pillar writes in
|
||||||
|
# update_version are no-ops here since the version is unchanged for a hotfix.
|
||||||
|
update_version
|
||||||
else
|
else
|
||||||
|
SOUP_UPGRADE_STARTED=true
|
||||||
echo ""
|
echo ""
|
||||||
echo "Performing upgrade from Security Onion $INSTALLEDVERSION to Security Onion $NEWVERSION."
|
echo "Performing upgrade from Security Onion $INSTALLEDVERSION to Security Onion $NEWVERSION."
|
||||||
echo ""
|
echo ""
|
||||||
@@ -1870,6 +1978,10 @@ main() {
|
|||||||
copy_new_files
|
copy_new_files
|
||||||
echo ""
|
echo ""
|
||||||
create_local_directories "/opt/so/saltstack/default"
|
create_local_directories "/opt/so/saltstack/default"
|
||||||
|
# Seed the resume marker before the highstate stamps /etc/soversion to the new
|
||||||
|
# version, so an interrupted upgrade is detectable as "not finished" on re-run.
|
||||||
|
# POSTVERSION still holds the pre-upgrade (or prior resume) version here.
|
||||||
|
[ -f "$POSTVERSION_FILE" ] || echo "$POSTVERSION" > "$POSTVERSION_FILE"
|
||||||
update_version
|
update_version
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -1531,7 +1531,8 @@ soc:
|
|||||||
agentic: false
|
agentic: false
|
||||||
agentMapping:
|
agentMapping:
|
||||||
Orchestrator: sonnet
|
Orchestrator: sonnet
|
||||||
Hunter: sonnet
|
Investigator: sonnet
|
||||||
|
Detection Engineer: sonnet
|
||||||
onionconfig:
|
onionconfig:
|
||||||
saltstackDir: /opt/so/saltstack
|
saltstackDir: /opt/so/saltstack
|
||||||
bypassEnabled: false
|
bypassEnabled: false
|
||||||
|
|||||||
@@ -783,8 +783,11 @@ soc:
|
|||||||
Orchestrator:
|
Orchestrator:
|
||||||
description: The initial agent in most agentic conversations. This agent will delegate requests to specialized agents.
|
description: The initial agent in most agentic conversations. This agent will delegate requests to specialized agents.
|
||||||
global: True
|
global: True
|
||||||
Hunter:
|
Investigator:
|
||||||
description: This agent is specialized in querying events.
|
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
|
||||||
|
Detection Engineer:
|
||||||
|
description: This agent manages detections and their overrides, including tuning noisy rules and authoring rule content.
|
||||||
global: True
|
global: True
|
||||||
client:
|
client:
|
||||||
assistant:
|
assistant:
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ suricata:
|
|||||||
cpu-affinity:
|
cpu-affinity:
|
||||||
management-cpu-set:
|
management-cpu-set:
|
||||||
cpu:
|
cpu:
|
||||||
description: Bind management threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used.
|
description: Bind management threads to a core or range of cores. This can be a single core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used.
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
helpLink: suricata
|
helpLink: suricata
|
||||||
worker-cpu-set:
|
worker-cpu-set:
|
||||||
cpu:
|
cpu:
|
||||||
description: Bind worker threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used.
|
description: Bind worker threads to a core or range of cores. This can be a single core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used.
|
||||||
forcedType: "[]string"
|
forcedType: "[]string"
|
||||||
helpLink: suricata
|
helpLink: suricata
|
||||||
vars:
|
vars:
|
||||||
|
|||||||
+1
-1
@@ -793,7 +793,7 @@ if ! [[ -f $install_opt_file ]]; then
|
|||||||
logCmd "so-soc-restart"
|
logCmd "so-soc-restart"
|
||||||
title "Setting up Elastic Fleet"
|
title "Setting up Elastic Fleet"
|
||||||
logCmd "salt-call state.apply elasticfleet.config"
|
logCmd "salt-call state.apply elasticfleet.config"
|
||||||
if ! logCmd so-elastic-fleet-setup; then
|
if ! so-elastic-fleet-setup; then
|
||||||
fail_setup "Failed to run so-elastic-fleet-setup"
|
fail_setup "Failed to run so-elastic-fleet-setup"
|
||||||
fi
|
fi
|
||||||
mark_setup_complete
|
mark_setup_complete
|
||||||
|
|||||||
Reference in New Issue
Block a user