Files
securityonion/setup/so-functions
Josh Patterson 578a18acbe Merge pull request #13853 from Security-Onion-Solutions/agcr
install createrepo for airgap
2024-10-23 14:21:26 -04:00

2333 lines
66 KiB
Bash
Executable File

#!/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.
# README - DO NOT DEFINE GLOBAL VARIABLES IN THIS FILE. Instead use so-variables.
### Begin Logging Section ###
log() {
msg=$1
level=${2:-I}
now=$(TZ=GMT date +"%Y-%m-%dT%H:%M:%SZ")
echo -e "$now | $level | $msg" 2>&1 | tee -a "$setup_log"
}
error() {
log "$1" "ERROR"
}
info() {
log "$1" "INFO"
}
title() {
echo -e "\n-----------------------------\n $1\n-----------------------------\n" >> "$setup_log" 2>&1
}
fail_setup() {
error "Setup encounted an unrecoverable failure, exiting"
touch /root/failure
exit 1
}
logCmd() {
cmd=$1
info "Executing command: $cmd"
$cmd 2>&1 | tee -a $setup_log
}
### End Logging Section ###
airgap_rules() {
# Copy the rules for detections if using Airgap
mkdir -p /nsm/rules
rsync -av /root/SecurityOnion/agrules/ /nsm/rules/
# Copy over the securityonion-resources repo
rsync -av /root/SecurityOnion/agrules/securityonion-resources /nsm/
}
airgap_detection_summaries() {
# Copy summaries over to SOC and checkout the correct branch
rsync -av --chown=socore:socore /nsm/securityonion-resources /opt/so/conf/soc/ai_summary_repos
git config --global --add safe.directory /opt/so/conf/soc/ai_summary_repos/securityonion-resources
git -C /opt/so/conf/soc/ai_summary_repos/securityonion-resources checkout generated-summaries-published
}
add_admin_user() {
title "Adding $ADMINUSER to the system with sudo rights"
logCmd "useradd '$ADMINUSER'"
echo "$ADMINUSER":"$ADMINPASS1" | chpasswd --crypt-method=SHA512
logCmd "usermod -aG wheel '$ADMINUSER'"
}
add_mngr_ip_to_hosts() {
info "Adding $MSRV to /etc/hosts with IP: $MSRVIP"
echo "$MSRVIP $MSRV" >> /etc/hosts
}
add_socore_user_manager() {
info "Adding socore user"
logCmd "so_add_user socore 939 939 /opt/so"
}
add_web_user() {
wait_for_file /nsm/kratos/db/db.sqlite 30 5
{
info "Attempting to add administrator user for web interface...";
echo "$WEBPASSWD1" | /usr/sbin/so-user add --email "$WEBUSER" --role "superuser";
info "Add user result: $?";
} >> "/root/so-user-add.log" 2>&1
}
analyze_system() {
title "System Characteristics"
logCmd "uptime"
logCmd "uname -a"
logCmd "free -h"
logCmd "lscpu"
logCmd "df -h"
logCmd "ip a"
}
desktop_salt_local() {
SALTVERSION=$(egrep 'version: [0-9]{4}' ../salt/salt/master.defaults.yaml | sed 's/^.*version: //')
# Install everything using local salt
# Set the repo
securityonion_repo
gpg_rpm_import
# Install salt
logCmd "yum -y install salt-minion-$SALTVERSION httpd-tools python3 python3-dateutil yum-utils device-mapper-persistent-data lvm2 openssl jq"
logCmd "yum -y update --exclude=salt*"
salt_install_module_deps
salt_patch_x509_v2
logCmd "salt-call state.apply desktop --local --file-root=../salt/ -l info"
read -r -d '' message <<- EOM
Finished Security Onion Desktop installation.
Press the Enter key to reboot.
EOM
if [[ -z "$TESTING" ]]; then
whiptail --title "$whiptail_title" --msgbox "$message" 12 75
reboot
fi
exit 0
}
desktop_pillar() {
local pillar_file=$local_salt_dir/pillar/minions/$MINION_ID.sls
# Create the desktop pillar
printf '%s\n'\
"host:"\
" mainint: '$MNIC'"\
"desktop:"\
" gui:"\
" enabled: true"\
"sensoroni:"\
" config:"\
" node_description: '${NODE_DESCRIPTION//\'/''}'" > $pillar_file
}
calculate_useable_cores() {
# Calculate reasonable core usage
local cores_for_zeek=$(( (num_cpu_cores/2) - 1 ))
local lb_procs_round
lb_procs_round=$(printf "%.0f\n" $cores_for_zeek)
if [ "$lb_procs_round" -lt 1 ]; then lb_procs=1; else lb_procs=$lb_procs_round; fi
export lb_procs
}
check_admin_pass() {
check_pass_match "$ADMINPASS1" "$ADMINPASS2" "APMATCH"
}
check_manager_connection() {
# See if you can curl the manager. If not you can either try again or continue
info "Checking manager connectivity"
man_test_err=$(curl -s $MSRVIP:4505 --connect-timeout 5 2>&1)
local ret=$?
if [[ $ret != 1 ]]; then
info "Could not reach $MSRV"
whiptail_manager_unreachable
fi
}
check_network_manager_conf() {
local gmdconf="/usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf"
local nmconf="/etc/NetworkManager/NetworkManager.conf"
local preupdir="/etc/NetworkManager/dispatcher.d/pre-up.d"
if test -f "$gmdconf" && ! test -f "${gmdconf}.bak"; then
{
mv "$gmdconf" "${gmdconf}.bak"
touch "$gmdconf"
systemctl restart NetworkManager
} >> "$setup_log" 2>&1
fi
if [[ ! -d "$preupdir" ]]; then
mkdir "$preupdir" >> "$setup_log" 2>&1
fi
}
check_pass_match() {
info "Making sure passwords match"
local pass=$1
local confirm_pass=$2
local var=$3
if [ "$pass" = "$confirm_pass" ]; then
export "$var=yes"
else
whiptail_passwords_dont_match
fi
}
# False if stopped, true if running
check_service_status() {
local service_name=$1
info "Checking service $service_name status"
systemctl status $service_name > /dev/null 2>&1
local status=$?
if [ $status -gt 0 ]; then
info " $service_name is not running"
return 1;
else
info " $service_name is running"
return 0;
fi
}
check_web_pass() {
info "Making sure web credential passwords match"
check_pass_match "$WEBPASSWD1" "$WEBPASSWD2" "WPMATCH"
}
clear_manager() {
# Clear out the old manager public key in case this is a re-install.
# This only happens if you re-install the manager.
if [ -f /etc/salt/pki/minion/minion_master.pub ]; then
info "Clearing old Salt master key"
logCmd "rm -f /etc/salt/pki/minion/minion_master.pub"
info "Restarting Salt Minion"
logCmd "systemctl -q restart salt-minion"
fi
}
collect_adminuser_inputs() {
whiptail_create_admin_user
while ! valid_username "$ADMINUSER"; do
whiptail_invalid_input
whiptail_create_admin_user "$ADMINUSER"
done
APMATCH=no
while [[ $APMATCH != yes ]]; do
whiptail_create_admin_user_password1
whiptail_create_admin_user_password2
check_admin_pass
done
}
collect_dns() {
whiptail_management_interface_dns "8.8.8.8,8.8.4.4"
while ! valid_dns_list "$MDNS"; do
whiptail_invalid_input
whiptail_management_interface_dns "$MDNS"
done
MDNS=$(echo "$MDNS" | tr -s "," " ") # MDNS needs to be space separated, we prompt for comma separated for consistency
}
collect_dns_domain() {
whiptail_management_interface_dns_search "searchdomain.local"
while ! valid_fqdn "$MSEARCH"; do
whiptail_invalid_input
whiptail_management_interface_dns_search "$MSEARCH"
done
}
collect_dockernet() {
if ! whiptail_dockernet_check; then
whiptail_dockernet_sosnet "172.17.1.0"
while ! valid_ip4 "$DOCKERNET" || [[ $DOCKERNET =~ "172.17.0." ]]; do
whiptail_invalid_input
whiptail_dockernet_sosnet "$DOCKERNET"
done
fi
}
collect_gateway() {
whiptail_management_interface_gateway
while ! valid_ip4 "$MGATEWAY"; do
whiptail_invalid_input
whiptail_management_interface_gateway "$MGATEWAY"
done
}
collect_hostname() {
collect_hostname_validate
while has_uppercase "$HOSTNAME"; do
if ! (whiptail_uppercase_warning); then
collect_hostname_validate
else
no_use_hostname=true
break
fi
done
}
collect_hostname_validate() {
if [[ -z "$TESTING" ]] && [[ "$HOSTNAME" == *'localhost'* ]]; then HOSTNAME=securityonion; fi
whiptail_set_hostname "$HOSTNAME"
if [[ -z $default_hostname_flag ]] && [[ $HOSTNAME == 'securityonion' ]]; then # Will only check HOSTNAME=securityonion once
if ! (whiptail_avoid_default_hostname); then
whiptail_set_hostname "$HOSTNAME"
fi
default_hostname_flag=true
fi
while ! valid_hostname "$HOSTNAME"; do
whiptail_invalid_hostname
whiptail_set_hostname "$HOSTNAME"
done
}
collect_idh_preferences() {
IDH_MGTRESTRICT='False'
whiptail_idh_preferences
if [[ "$idh_preferences" != "" ]]; then IDH_MGTRESTRICT='True'; fi
}
collect_int_ip_mask() {
whiptail_management_interface_ip_mask
while ! valid_ip4_cidr_mask "$manager_ip_mask"; do
whiptail_invalid_input
whiptail_management_interface_ip_mask "$manager_ip_mask"
done
MIP=$(echo "$manager_ip_mask" | sed 's/\/.*//' )
MMASK=$(echo "$manager_ip_mask" | sed 's/.*\///')
}
collect_mngr_hostname() {
whiptail_management_server
while ! valid_hostname "$MSRV"; do
whiptail_invalid_hostname
whiptail_management_server "$MSRV"
done
while [[ $MSRV == "$HOSTNAME" ]]; do
whiptail_invalid_hostname 0
whiptail_management_server "$MSRV"
done
# Remove the manager from /etc/hosts incase a user entered the wrong IP when prompted
# and they are going through the installer again
if [[ "$HOSTNAME" != "$MSRV" ]]; then
info "Removing $MSRV from /etc/hosts if present."
sed -i "/$MSRV/d" /etc/hosts
fi
if [[ -z "$MSRVIP" ]]; then
if ! getent hosts "$MSRV"; then
whiptail_manager_ip
while ! valid_ip4 "$MSRVIP" || [[ $MSRVIP == "$MAINIP" || $MSRVIP == "127.0.0.1" ]]; do
whiptail_invalid_input
whiptail_manager_ip "$MSRVIP"
done
else
MSRVIP=$(getent hosts "$MSRV" | awk 'NR==1{print $1}')
whiptail_manager_ip "$MSRVIP"
while ! valid_ip4 "$MSRVIP" || [[ $MSRVIP == "$MAINIP" || $MSRVIP == "127.0.0.1" ]]; do
whiptail_invalid_input
whiptail_manager_ip "$MSRVIP"
done
fi
fi
}
collect_net_method() {
whiptail_net_method
if [[ "$network_traffic" == "PROXY"* ]]; then
collect_proxy no_ask
needs_proxy=true
fi
}
collect_proxy() {
[[ -n $TESTING ]] && return
local ask=${1:-true}
collect_proxy_details "$ask" || return
while ! proxy_validate; do
if whiptail_invalid_proxy; then
collect_proxy_details no_ask
else
so_proxy=""
break
fi
done
}
collect_proxy_details() {
local ask=${1:-true}
local use_proxy
if [[ $ask != true ]]; then
use_proxy=0
else
whiptail_proxy_ask
use_proxy=$?
fi
if [[ $use_proxy == 0 ]]; then
whiptail_proxy_addr "$proxy_addr"
while ! valid_proxy "$proxy_addr"; do
whiptail_invalid_input
whiptail_proxy_addr "$proxy_addr"
done
if whiptail_proxy_auth_ask; then
whiptail_proxy_auth_user "$proxy_user"
whiptail_proxy_auth_pass "$proxy_pass"
local url_prefixes=( 'http://' 'https://' )
for prefix in "${url_prefixes[@]}"; do
if echo "$proxy_addr" | grep -q "$prefix"; then
local proxy=${proxy_addr#"$prefix"}
so_proxy="${prefix}${proxy_user}:${proxy_pass}@${proxy}"
break
fi
done
else
so_proxy="$proxy_addr"
fi
export so_proxy
else
return 1
fi
}
collect_redirect_host() {
collect_redirect_host_validate
while has_uppercase "$REDIRECTHOST"; do
local text
! valid_hostname "$REDIRECTHOST" && text="domain name" || text="hostname"
if ! (whiptail_uppercase_warning "$text"); then
collect_redirect_host_validate "$REDIRECTHOST"
else
break
fi
done
}
collect_redirect_host_validate() {
local prefill=${1:-$HOSTNAME}
whiptail_set_redirect_host "$prefill"
while ! valid_ip4 "$REDIRECTHOST" && ! valid_hostname "$REDIRECTHOST" && ! valid_fqdn "$REDIRECTHOST"; do
whiptail_invalid_input
whiptail_set_redirect_host "$REDIRECTHOST"
done
}
collect_so_allow() {
if whiptail_so_allow_yesno; then
whiptail_so_allow
while ! valid_cidr "$ALLOW_CIDR" && ! valid_ip4 "$ALLOW_CIDR"; do
whiptail_invalid_input
whiptail_so_allow "$ALLOW_CIDR"
done
fi
}
# Get an email & password for the web admin user
collect_webuser_inputs() {
whiptail_create_web_user
while ! so-user valemail --email "$WEBUSER" >> "$setup_log" 2>&1; do
whiptail_invalid_user_warning
whiptail_create_web_user "$WEBUSER"
done
WPMATCH=no
while [[ $WPMATCH != yes ]]; do
whiptail_create_web_user_password1
while ! check_password "$WEBPASSWD1"; do
whiptail_invalid_pass_characters_warning
whiptail_create_web_user_password1
done
if echo "$WEBPASSWD1" | so-user valpass >> "$setup_log" 2>&1; then
whiptail_create_web_user_password2
check_web_pass
else
whiptail_invalid_pass_warning
fi
done
}
configure_minion() {
local minion_type=$1
if [[ $is_desktop ]]; then
minion_type=desktop
fi
info "Configuring minion type as $minion_type"
echo "role: so-$minion_type" > /etc/salt/grains
local minion_config=/etc/salt/minion
echo "id: '$MINION_ID'" > "$minion_config"
case "$minion_type" in
'workstation')
echo "master: '$MSRV'" >> "$minion_config"
;;
'manager' | 'eval' | 'managersearch' | 'standalone' | 'import')
cp -f ../salt/ca/files/signing_policies.conf /etc/salt/minion.d/signing_policies.conf
printf '%s\n'\
"master: '$HOSTNAME'"\
"mysql.host: '$MAINIP'"\
"mysql.port: '3306'"\
"mysql.user: 'root'" >> "$minion_config"
if [ ! -f $local_salt_dir/pillar/secrets.sls ]; then
echo "mysql.pass: '$MYSQLPASS'" >> "$minion_config"
else
OLDPASS=$(grep "mysql" $local_salt_dir/pillar/secrets.sls | awk '{print $2}')
echo "mysql.pass: '$OLDPASS'" >> "$minion_config"
fi
;;
*)
echo "master: '$MSRV'" >> "$minion_config"
;;
esac
printf '%s\n'\
"use_superseded:"\
" - module.run"\
"features:"\
" x509_v2: true"\
"log_level: info"\
"log_level_logfile: info"\
"log_file: /opt/so/log/salt/minion"\
"#startup_states: highstate" >> "$minion_config"
info "Running: salt-call state.apply salt.mine_functions --local --file-root=../salt/ -l info pillar='{"host": {"mainint": "$MNIC"}}'"
salt-call state.apply salt.mine_functions --local --file-root=../salt/ -l info pillar="{'host': {'mainint': $MNIC}}"
{
logCmd "systemctl enable salt-minion";
logCmd "systemctl restart salt-minion";
} >> "$setup_log" 2>&1
}
checkin_at_boot() {
local minion_config=/etc/salt/minion
info "Enabling checkin at boot"
sed -i 's/#startup_states: highstate/startup_states: highstate/' "$minion_config"
}
check_requirements() {
local req_mem
local req_cores
local req_storage
local nic_list
readarray -t nic_list <<< "$(ip link| awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}' | grep -vwe "bond0" | sed 's/ //g' | sed -r 's/(.*)(\.[0-9]+)@\1/\1\2/g')"
local num_nics=${#nic_list[@]}
if [[ $is_eval ]]; then
req_mem=8
req_cores=4
req_nics=2
elif [[ $is_standalone ]]; then
req_mem=16
req_cores=4
req_nics=2
elif [[ $is_manager ]]; then
req_mem=16
req_cores=4
req_nics=1
elif [[ $is_managersearch ]]; then
req_mem=16
req_cores=8
req_nics=1
elif [[ $is_sensor ]]; then
req_mem=12
req_cores=4
req_nics=2
elif [[ $is_fleet ]]; then
req_mem=4
req_cores=4
req_nics=1
elif [[ $is_searchnode ]]; then
req_mem=16
req_cores=4
req_nics=1
elif [[ $is_heavynode ]]; then
req_mem=16
req_cores=4
req_nics=2
elif [[ $is_idh ]]; then
req_mem=1
req_cores=2
req_nics=1
elif [[ $is_import ]]; then
req_mem=4
req_cores=2
req_nics=1
elif [[ $is_receiver ]]; then
req_mem=8
req_cores=2
req_nics=1
fi
if [[ $setup_type == 'network' ]] ; then
if [[ -n $nsm_mount ]]; then # does a /nsm mount exist
if [[ $is_import ]]; then
req_storage=50
elif [[ $is_idh ]]; then
req_storage=12
else
req_storage=100
fi
if [[ $free_space_root -lt $req_storage ]]; then
whiptail_storage_requirements "/" "${free_space_root} GB" "${req_storage} GB"
fi
if [[ $free_space_nsm -lt $req_storage ]]; then
whiptail_storage_requirements "/nsm" "${free_space_nsm} GB" "${req_storage} GB"
fi
else
if [[ $is_import ]]; then
req_storage=50
elif [[ $is_idh ]]; then
req_storage=12
else
req_storage=200
fi
if [[ $free_space_root -lt $req_storage ]]; then
whiptail_storage_requirements "/" "${free_space_root} GB" "${req_storage} GB"
fi
fi
fi
if [[ $num_nics -lt $req_nics ]]; then
if [[ $num_nics -eq 1 ]]; then
whiptail_requirements_error "NIC" "$num_nics" "$req_nics"
else
whiptail_requirements_error "NICs" "$num_nics" "$req_nics"
fi
fi
if [[ $num_cpu_cores -lt $req_cores ]]; then
if [[ $num_cpu_cores -eq 1 ]]; then
whiptail_requirements_error "core" "$num_cpu_cores" "$req_cores"
else
whiptail_requirements_error "cores" "$num_cpu_cores" "$req_cores"
fi
fi
if [[ $total_mem_hr -lt $req_mem ]]; then
whiptail_requirements_error "memory" "${total_mem_hr} GB" "${req_mem} GB"
if [[ $is_standalone || $is_heavynode ]]; then
echo "This install type will fail with less than $req_mem GB of memory. Exiting setup."
exit 0
fi
fi
if [[ $is_standalone || $is_heavynode ]]; then
if [[ $total_mem_hr -gt 15 && $total_mem_hr -lt 24 ]]; then
low_mem=true
else
low_mem=false
fi
fi
}
check_sos_appliance() {
if [ -f "/etc/SOSMODEL" ]; then
local MODEL=$(cat /etc/SOSMODEL)
info "Found SOS Model $MODEL"
echo "sosmodel: $MODEL" >> /etc/salt/grains
else
info "Not an appliance"
fi
}
compare_main_nic_ip() {
if ! [[ $MNIC =~ ^(tun|wg|vpn).*$ ]]; then
if [[ "$MAINIP" != "$MNIC_IP" ]]; then
error "[ERROR] Main gateway ($MAINIP) does not match ip address of management NIC ($MNIC_IP)."
read -r -d '' message <<- EOM
The IP being routed by Linux is not the IP address assigned to the management interface ($MNIC).
This is not a supported configuration, please remediate
and rerun setup.
EOM
[[ -n $TESTING ]] || whiptail --title "$whiptail_title" --msgbox "$message" 11 75
kill -SIGINT "$(ps --pid $$ -oppid=)"; fail_setup
fi
else
# Setup uses MAINIP, but since we ignore the equality condition when using a VPN
# just set the variable to the IP of the VPN interface
MAINIP=$MNIC_IP
fi
}
configure_network_sensor() {
info "Setting up sensor interface"
if [[ $is_cloud ]]; then
info "Configuring traditional interface settings, since this is a cloud installation..."
local nmcli_con_args=( "type" "ethernet" )
else
info "Configuring bond interface settings, since this is a not a cloud installation..."
local nmcli_con_args=( "type" "bond" "mode" "0" )
fi
# Create the bond interface only if it doesn't already exist
nmcli -f name,uuid -p con | grep -q '$INTERFACE'
local found_int=$?
if [[ $found_int != 0 ]]; then
nmcli con add ifname "$INTERFACE" con-name "$INTERFACE" "${nmcli_con_args[@]}" -- \
ipv4.method disabled \
ipv6.method ignore \
ethernet.mtu "$MTU" \
connection.autoconnect "yes" >> "$setup_log" 2>&1
else
local int_uuid
int_uuid=$(nmcli -f name,uuid -p con | sed -n "s/$INTERFACE //p" | tr -d ' ')
nmcli con mod "$int_uuid" \
ipv4.method disabled \
ipv6.method ignore \
ethernet.mtu "$MTU" \
connection.autoconnect "yes" >> "$setup_log" 2>&1
fi
local err=0
for BNIC in "${BNICS[@]}"; do
add_interface_bond0 "$BNIC" --verbose >> "$setup_log" 2>&1
local ret=$?
[[ $ret -eq 0 ]] || err=$ret
done
return $err
}
copy_salt_master_config() {
title "Copy the Salt master config template to the proper directory"
if [ "$setup_type" = 'iso' ]; then
logCmd "cp /root/SecurityOnion/files/salt/master/master /etc/salt/master"
#logCmd "cp /root/SecurityOnion/files/salt/master/salt-master.service /usr/lib/systemd/system/salt-master.service"
else
logCmd "cp ../files/salt/master/master /etc/salt/master"
#logCmd "cp ../files/salt/master/salt-master.service /usr/lib/systemd/system/salt-master.service"
fi
info "Copying pillar and salt files in $temp_install_dir to $local_salt_dir"
logCmd "cp -Rv $temp_install_dir/pillar/ $local_salt_dir/"
if [ -d "$temp_install_dir"/salt ] ; then
logCmd "cp -Rv $temp_install_dir/salt/ $local_salt_dir/"
fi
# Restart the service so it picks up the changes
logCmd "systemctl daemon-reload"
logCmd "systemctl enable salt-master"
logCmd "systemctl restart salt-master"
}
create_local_nids_rules() {
title "Create a local.rules file so it doesn't get removed on updates"
logCmd "mkdir -p /opt/so/saltstack/local/salt/idstools"
echo "# Custom Suricata rules go in this file" > /opt/so/saltstack/local/salt/idstools/local.rules
logCmd "salt-run fileserver.clear_file_list_cache"
}
create_manager_pillars() {
elasticfleet_pillar
elasticsearch_pillar
logstash_pillar
manager_pillar
create_global
create_sensoroni_pillar
backup_pillar
docker_pillar
redis_pillar
idstools_pillar
kratos_pillar
soc_pillar
idh_pillar
influxdb_pillar
logrotate_pillar
patch_pillar
nginx_pillar
kibana_pillar
kafka_pillar
}
create_repo() {
title "Create the repo directory"
logCmd "dnf -y install yum-utils createrepo_c"
logCmd "createrepo /nsm/repo"
}
detect_cloud() {
info "Testing if setup is running on a cloud instance..."
if [ -f /etc/SOCLOUD ] || \
dmidecode -s bios-version 2>&1 | grep -q amazon || \
dmidecode -s bios-vendor 2>&1 | grep -q Amazon || \
dmidecode -s bios-vendor 2>&1 | grep -q Google || \
[ -f /var/log/waagent.log ]; then
info "Detected a cloud installation..."
export is_cloud="true"
else
info "This does not appear to be a cloud installation."
fi
}
detect_os() {
title "Detecting Base OS"
if [ -f /etc/redhat-release ]; then
if grep -q "Rocky Linux release 9" /etc/redhat-release; then
OS=rocky
OSVER=9
is_rocky=true
is_rpm=true
not_supported=true
unset is_supported
elif grep -q "CentOS Stream release 9" /etc/redhat-release; then
OS=centos
OSVER=9
is_centos=true
is_rpm=true
not_supported=true
unset is_supported
elif grep -q "AlmaLinux release 9" /etc/redhat-release; then
OS=alma
OSVER=9
is_alma=true
is_rpm=true
not_supported=true
unset is_supported
elif grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release; then
if [ -f /etc/oracle-release ]; then
OS=oracle
OSVER=9
is_oracle=true
is_rpm=true
is_supported=true
else
OS=rhel
OSVER=9
is_rhel=true
is_rpm=true
not_supported=true
unset is_supported
fi
fi
elif [ -f /etc/os-release ]; then
if grep -q "UBUNTU_CODENAME=focal" /etc/os-release; then
OSVER=focal
UBVER=20.04
OS=ubuntu
is_ubuntu=true
is_deb=true
not_supported=true
unset is_supported
elif grep -q "UBUNTU_CODENAME=jammy" /etc/os-release; then
OSVER=jammy
UBVER=22.04
OS=ubuntu
is_ubuntu=true
is_deb=true
not_supported=true
unset is_supported
elif grep -q "VERSION_CODENAME=bookworm" /etc/os-release; then
OSVER=bookworm
DEBVER=12
is_debian=true
OS=debian
is_deb=true
not_supported=true
unset is_supported
fi
installer_prereq_packages
else
info "We were unable to determine if you are using a supported OS."
fail_setup
fi
info "Found OS: $OS $OSVER"
}
download_elastic_agent_artifacts() {
if ! update_elastic_agent 2>&1 | tee -a "$setup_log"; then
fail_setup
fi
}
installer_prereq_packages() {
if [[ $is_deb ]]; then
# Print message to stdout so the user knows setup is doing something
info "Running apt-get update"
retry 150 10 "apt-get update" "" "Err:" >> "$setup_log" 2>&1 || fail_setup
# Install network manager so we can do interface stuff
if ! command -v nmcli > /dev/null 2>&1; then
info "Installing network-manager"
retry 150 10 "apt-get -y install network-manager ethtool" >> "$setup_log" 2>&1 || fail_setup
logCmd "systemctl enable NetworkManager"
logCmd "systemctl start NetworkManager"
fi
if ! command -v curl > /dev/null 2>&1; then
retry 150 10 "apt-get -y install curl" >> "$setup_log" 2>&1 || fail_setup
fi
fi
}
disable_auto_start() {
if crontab -l -u $INSTALLUSERNAME 2>&1 | grep -q so-setup; then
# Remove the automated setup script from crontab, if it exists
logCmd "crontab -u $INSTALLUSERNAME -r"
fi
if grep -s -q so-setup /home/$INSTALLUSERNAME/.bash_profile; then
# Truncate last line of the bash profile
info "Removing auto-run of setup from bash profile"
sed -i '$ d' /home/$INSTALLUSERNAME/.bash_profile >> "$setup_log" 2>&1
fi
}
disable_ipv6() {
{
info "Disabling ipv6"
logCmd "sysctl -w net.ipv6.conf.all.disable_ipv6=1"
logCmd "sysctl -w net.ipv6.conf.default.disable_ipv6=1"
} >> "$setup_log" 2>&1
{
echo "net.ipv6.conf.all.disable_ipv6 = 1"
echo "net.ipv6.conf.default.disable_ipv6 = 1"
echo "net.ipv6.conf.lo.disable_ipv6 = 1"
} >> /etc/sysctl.conf
}
docker_seed_update() {
local name=$1
local percent_delta=1
((docker_seed_update_percent+=percent_delta))
set_progress_str "$docker_seed_update_percent" "Downloading $name"
}
docker_seed_registry() {
local VERSION="$SOVERSION"
if ! [ -f /nsm/docker-registry/docker/registry.tar ]; then
if [ "$install_type" == 'IMPORT' ]; then
container_list 'so-import'
else
container_list
fi
docker_seed_update_percent=25
update_docker_containers 'netinstall' '' 'docker_seed_update' '/dev/stdout' 2>&1 | tee -a "$setup_log"
else
logCmd "tar xvf /nsm/docker-registry/docker/registry.tar -C /nsm/docker-registry/docker"
logCmd "rm /nsm/docker-registry/docker/registry.tar"
fi
}
elasticfleet_pillar() {
logCmd "mkdir -p $local_salt_dir/pillar/elasticfleet"
touch $adv_elasticfleet_pillar_file
touch $elasticfleet_pillar_file
}
elasticsearch_pillar() {
title "Create Advanced File"
logCmd "touch $adv_elasticsearch_pillar_file"
# Create the Elasticsearch pillar
printf '%s\n'\
"elasticsearch:"\
" config:"\
" cluster:"\
" name: securityonion"\
" routing:"\
" allocation:"\
" disk:"\
" threshold_enabled: true"\
" watermark:"\
" low: 80%"\
" high: 85%"\
" flood_stage: 90%"\
" script:"\
" max_compilations_rate: 20000/1m"\
" indices:"\
" query:"\
" bool:"\
" max_clause_count: 3500"\
" index_settings: {}" > $elasticsearch_pillar_file
}
es_heapsize() {
title "Determine ES Heap Size"
if [ "$total_mem" -lt 8000 ] ; then
ES_HEAP_SIZE="600m"
elif [ "$total_mem" -ge 100000 ]; then
# Set a max of 25GB for heap size
# https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html
ES_HEAP_SIZE="25000m"
else
# Set heap size to 33% of available memory
ES_HEAP_SIZE=$(( total_mem / 3 ))
if [ "$ES_HEAP_SIZE" -ge 25001 ] ; then
ES_HEAP_SIZE="25000m"
else
ES_HEAP_SIZE=$ES_HEAP_SIZE"m"
fi
fi
export ES_HEAP_SIZE
if [[ "$install_type" =~ ^(EVAL|MANAGERSEARCH|STANDALONE|IMPORT)$ ]]; then
NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE
export NODE_ES_HEAP_SIZE
fi
}
filter_unused_nics() {
if [[ $MNIC ]]; then local grep_string="$MNIC\|bond0"; else local grep_string="bond0"; fi
# If we call this function and NICs have already been assigned to the bond interface then add them to the grep search string
if [[ $BNICS ]]; then
grep_string="$grep_string"
for BONDNIC in "${BNICS[@]}"; do
grep_string="$grep_string\|$BONDNIC"
done
fi
# Finally, set filtered_nics to any NICs we aren't using (and ignore interfaces that aren't of use)
filtered_nics=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}' | grep -vwe "$grep_string" | sed 's/ //g' | sed -r 's/(.*)(\.[0-9]+)@\1/\1\2/g')
readarray -t filtered_nics <<< "$filtered_nics"
nic_list=()
nic_list_management=()
for nic in "${filtered_nics[@]}"; do
local nic_mac=$(cat "/sys/class/net/${nic}/address" 2>/dev/null)
case $(cat "/sys/class/net/${nic}/carrier" 2>/dev/null) in
1)
nic_list+=("$nic" "$nic_mac Link UP " "OFF")
nic_list_management+=("$nic" "$nic_mac Link UP " )
;;
0)
nic_list+=("$nic" "$nic_mac Link DOWN " "OFF")
nic_list_management+=("$nic" "$nic_mac Link DOWN " )
;;
*)
nic_list+=("$nic" "$nic_mac Link UNKNOWN " "OFF")
nic_list_management+=("$nic" "$nic_mac Link UNKNOWN " )
;;
esac
done
export nic_list nic_list_management
}
# Generate Firewall Templates
firewall_generate_templates() {
title "Generate Firewall Template"
local firewall_pillar_path=$local_salt_dir/salt/firewall
logCmd "mkdir -p $firewall_pillar_path"
logCmd "cp -r ../files/firewall/* /opt/so/saltstack/local/salt/firewall/"
}
generate_ca() {
title "Generating the certificate authority"
logCmd "salt-call state.apply ca -l info"
info "Confirming existence of the CA certificate"
logCmd "openssl x509 -in /etc/pki/ca.crt -noout -subject -issuer -dates"
}
generate_ssl() {
# if the install type is a manager then we need to wait for the minion to be ready before trying
# to run the ssl state since we need the minion to sign the certs
if [[ "$install_type" =~ ^(EVAL|MANAGER|MANAGERSEARCH|STANDALONE|IMPORT|HELIXSENSOR)$ ]]; then
(wait_for_salt_minion "$MINION_ID" "5" '/dev/stdout' || fail_setup) 2>&1 | tee -a "$setup_log"
fi
info "Applying SSL state"
logCmd "salt-call state.apply ssl -l info"
}
generate_passwords(){
title "Generate Random Passwords"
INFLUXPASS=$(get_random_value)
INFLUXTOKEN=$(head -c 64 /dev/urandom | base64 --wrap=0)
SENSORONIKEY=$(get_random_value)
KRATOSKEY=$(get_random_value)
REDISPASS=$(get_random_value)
SOCSRVKEY=$(get_random_value 64)
IMPORTPASS=$(get_random_value)
}
generate_interface_vars() {
title "Setting the MTU to 9000 on all monitor NICS"
MTU=9000
export MTU
# Set interface variable
if [[ $is_cloud ]]; then
INTERFACE=${BNICS[0]}
else
INTERFACE='bond0'
fi
info "Interface set to $INTERFACE"
export INTERFACE
}
get_redirect() {
whiptail_set_redirect
if [ "$REDIRECTINFO" = "OTHER" ]; then
collect_redirect_host
fi
}
get_minion_type() {
local minion_type
case "$install_type" in
'EVAL' | 'MANAGERSEARCH' | 'MANAGER' | 'SENSOR' | 'HEAVYNODE' | 'SEARCHNODE' | 'FLEET' | 'IDH' | 'STANDALONE' | 'IMPORT' | 'RECEIVER' | 'DESKTOP')
minion_type=$(echo "$install_type" | tr '[:upper:]' '[:lower:]')
;;
esac
echo "$minion_type"
}
install_cleanup() {
if [ -f "$temp_install_dir" ]; then
info "Installer removing the following files:"
logCmd "ls -lR $temp_install_dir"
# Clean up after ourselves
logCmd "rm -rf $temp_install_dir"
fi
# All cleanup prior to this statement must be compatible with automated testing. Cleanup
# that will disrupt automated tests should be placed beneath this statement.
[ -n "$TESTING" ] && return
if [[ $setup_type == 'iso' ]]; then
info "Removing so-setup permission entry from sudoers file"
logCmd "sed -i '/so-setup/d' /etc/sudoers"
fi
if [[ -z $SO_ERROR ]]; then
info "Setup completed at $(date)"
fi
}
import_registry_docker() {
if [ -f /nsm/docker-registry/docker/registry_image.tar ]; then
logCmd "service docker start"
logCmd "docker load -i /nsm/docker-registry/docker/registry_image.tar"
else
info "Need to download registry"
fi
}
idh_pillar() {
touch $adv_idh_pillar_file
}
kibana_pillar() {
logCmd "mkdir -p $local_salt_dir/pillar/kibana"
logCmd "touch $adv_kibana_pillar_file"
logCmd "touch $kibana_pillar_file"
}
kafka_pillar() {
KAFKACLUSTERID=$(get_random_value 22)
KAFKAPASS=$(get_random_value)
KAFKATRUST=$(get_random_value)
logCmd "mkdir -p $local_salt_dir/pillar/kafka"
logCmd "touch $adv_kafka_pillar_file"
logCmd "touch $kafka_pillar_file"
printf '%s\n'\
"kafka:"\
" cluster_id: $KAFKACLUSTERID"\
" config:"\
" password: $KAFKAPASS"\
" trustpass: $KAFKATRUST" > $kafka_pillar_file
}
logrotate_pillar() {
logCmd "mkdir -p $local_salt_dir/pillar/logrotate"
logCmd "touch $adv_logrotate_pillar_file"
logCmd "touch $logrotate_pillar_file"
}
patch_pillar() {
touch $adv_patch_pillar_file
touch $patch_pillar_file
}
logstash_pillar() {
# Create the logstash advanced pillar
touch $adv_logstash_pillar_file
touch $logstash_pillar_file
}
# Set Logstash heap size based on total memory
ls_heapsize() {
title "Setting Logstash heap size"
if [ "$total_mem" -ge 32000 ]; then
LS_HEAP_SIZE='1000m'
return
fi
case "$install_type" in
'MANAGERSEARCH' | 'HEAVYNODE' | 'STANDALONE')
LS_HEAP_SIZE='1000m'
;;
'EVAL')
LS_HEAP_SIZE='700m'
;;
*)
LS_HEAP_SIZE='500m'
;;
esac
export LS_HEAP_SIZE
}
idstools_pillar() {
title "Ading IDSTOOLS pillar options"
touch $adv_idstools_pillar_file
}
nginx_pillar() {
title "Creating the NGINX pillar"
[[ -z "$TESTING" ]] && return
# When testing, set the login rate limiting to high values to avoid failing automated logins
printf '%s\n'\
"nginx:"\
" config:"\
" throttle_login_burst: 9999"\
" throttle_login_rate: 9999"\
"" > "$nginx_pillar_file"
}
soc_pillar() {
title "Creating the SOC pillar"
touch $adv_soc_pillar_file
printf '%s\n'\
"soc:"\
" config:"\
" server:"\
" srvKey: '$SOCSRVKEY'" > "$soc_pillar_file"
if [[ $telemetry -ne 0 ]]; then
echo " telemetryEnabled: false" >> $soc_pillar_file
fi
}
telegraf_pillar() {
title "Creating telegraf pillar"
touch $adv_telegraf_pillar_file
touch $telegraf_pillar_file
}
manager_pillar() {
touch $adv_manager_pillar_file
title "Create the manager pillar"
printf '%s\n'\
"manager:"\
" proxy: '$so_proxy'"\
" no_proxy: '$no_proxy_string'"\
" elastalert: 1"\
"" > "$manager_pillar_file"
}
kratos_pillar() {
title "Create the Kratos pillar file"
touch $adv_kratos_pillar_file
printf '%s\n'\
"kratos:"\
" config:"\
" secrets:"\
" default:"\
" - '$KRATOSKEY'"\
"" > "$kratos_pillar_file"
}
create_global() {
title "Creating the global.sls"
touch $adv_global_pillar_file
if [ -z "$NODE_CHECKIN_INTERVAL_MS" ]; then
NODE_CHECKIN_INTERVAL_MS=10000
if [ "$install_type" = 'EVAL' ] || [ "$install_type" = 'STANDALONE' ] || [ "$install_type" = 'IMPORT' ]; then
NODE_CHECKIN_INTERVAL_MS=1000
fi
fi
if [ -f "$global_pillar_file" ]; then
rm $global_pillar_file
fi
# Create a global file for global values
echo "global:" >> $global_pillar_file
echo " soversion: '$SOVERSION'" >> $global_pillar_file
echo " managerip: '$MAINIP'" >> $global_pillar_file
echo " mdengine: 'ZEEK'" >> $global_pillar_file
echo " ids: 'Suricata'" >> $global_pillar_file
echo " url_base: '$REDIRECTIT'" >> $global_pillar_file
if [[ $HIGHLANDER == 'True' ]]; then
echo " highlander: True" >> $global_pillar_file
fi
if [[ $is_airgap ]]; then
echo " airgap: True" >> $global_pillar_file
else
echo " airgap: False" >> $global_pillar_file
fi
# Continue adding other details
echo " imagerepo: '$IMAGEREPO'" >> $global_pillar_file
echo " repo_host: '$HOSTNAME'" >> $global_pillar_file
echo " influxdb_host: '$HOSTNAME'" >> $global_pillar_file
echo " registry_host: '$HOSTNAME'" >> $global_pillar_file
echo " endgamehost: '$ENDGAMEHOST'" >> $global_pillar_file
if [[ $is_standalone || $is_eval ]]; then
echo " pcapengine: SURICATA" >> $global_pillar_file
fi
}
create_sensoroni_pillar() {
title "Create the sensoroni pillar file"
touch $adv_sensoroni_pillar_file
printf '%s\n'\
"sensoroni:"\
" config:"\
" node_checkin_interval_ms: $NODE_CHECKIN_INTERVAL_MS"\
" sensoronikey: '$SENSORONIKEY'"\
" soc_host: '$REDIRECTIT'" > $sensoroni_pillar_file
}
backup_pillar() {
title "Create the backup pillar file"
touch $adv_backup_pillar_file
}
docker_pillar() {
title "Create the docker pillar file"
touch $adv_docker_pillar_file
touch $docker_pillar_file
if [ ! -z "$DOCKERNET" ]; then
DOCKERGATEWAY=$(echo $DOCKERNET | awk -F'.' '{print $1,$2,$3,1}' OFS='.')
printf '%s\n'\
"docker:"\
" range: '$DOCKERNET/24'"\
" gateway: '$DOCKERGATEWAY'" > $docker_pillar_file
fi
}
redis_pillar() {
title "Create the redis pillar file"
touch $adv_redis_pillar_file
printf '%s\n'\
"redis:"\
" config:"\
" requirepass: '$REDISPASS'" > $redis_pillar_file
}
influxdb_pillar() {
title "Create the influxdb pillar file"
touch $adv_influxdb_pillar_file
touch $influxdb_pillar_file
printf '%s\n'\
"influxdb:"\
" token: $INFLUXTOKEN" > $local_salt_dir/pillar/influxdb/token.sls
}
make_some_dirs() {
mkdir -p /nsm
mkdir -p "$default_salt_dir"
mkdir -p "$local_salt_dir"
mkdir -p $local_salt_dir/pillar/minions
mkdir -p $local_salt_dir/salt/firewall/hostgroups
mkdir -p $local_salt_dir/salt/firewall/portgroups
mkdir -p $local_salt_dir/salt/firewall/ports
for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos idstools idh elastalert stig global kafka versionlock; do
mkdir -p $local_salt_dir/pillar/$THEDIR
touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls
touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls
done
}
mark_version() {
title "Marking the current version"
echo "$SOVERSION" > /etc/soversion
}
network_init() {
title "Initializing Network"
disable_ipv6
set_hostname
if [[ ( $is_iso || $is_desktop_iso || $is_debian ) ]]; then
set_management_interface
fi
}
network_init_whiptail() {
case "$setup_type" in
'iso')
whiptail_management_nic
whiptail_dhcp_or_static
if [ "$address_type" != 'DHCP' ]; then
collect_int_ip_mask
collect_gateway
collect_dns
collect_dns_domain
fi
;;
'network')
whiptail_network_notice
whiptail_dhcp_warn
whiptail_management_nic
;;
esac
}
networking_needful() {
[[ -f $net_init_file ]] && whiptail_net_reinit && reinit_networking=true
if [[ $reinit_networking ]] || ! [[ -f $net_init_file ]]; then
collect_hostname
fi
[[ ! ( $is_eval || $is_import ) ]] && whiptail_node_description
if [[ $reinit_networking ]] || ! [[ -f $net_init_file ]]; then
network_init_whiptail
else
source "$net_init_file"
fi
if [[ $reinit_networking ]] || ! [[ -f $net_init_file ]]; then
network_init
fi
set_main_ip
compare_main_nic_ip
# Attempt to autodetect the manager IP, if an offset value exists
if [[ -n "$MSRVIP_OFFSET" && -z "$MSRVIP" ]]; then
mips1=$(echo "$MNIC_IP" | awk -F. '{print $1}')
mips2=$(echo "$MNIC_IP" | awk -F. '{print $2}')
mips3=$(echo "$MNIC_IP" | awk -F. '{print $3}')
mips4=$(echo "$MNIC_IP" | awk -F. '{print $4}')
MSRVIP="$mips1.$mips2.$mips3.$((mips4+$MSRVIP_OFFSET))"
fi
}
network_setup() {
info "Finishing up network setup"
info "... Copying 99-so-checksum-offload-disable"
logCmd "cp ./install_scripts/99-so-checksum-offload-disable /etc/NetworkManager/dispatcher.d/pre-up.d/99-so-checksum-offload-disable"
info "... Modifying 99-so-checksum-offload-disable";
logCmd "sed -i '/\$MNIC/${INTERFACE}/g' /etc/NetworkManager/dispatcher.d/pre-up.d/99-so-checksum-offload-disable"
}
parse_install_username() {
# parse out the install username so things copy correctly
INSTALLUSERNAME=${SUDO_USER:-${USER}}
}
print_salt_state_apply() {
local state=$1
info "Applying $state Salt state"
}
process_installtype() {
if [ "$install_type" = 'EVAL' ]; then
is_eval=true
STRELKARULES=1
elif [ "$install_type" = 'STANDALONE' ]; then
is_standalone=true
elif [ "$install_type" = 'MANAGERSEARCH' ]; then
is_managersearch=true
elif [ "$install_type" = 'MANAGER' ]; then
is_manager=true
elif [ "$install_type" = 'SENSOR' ]; then
is_sensor=true
elif [ "$install_type" = 'SEARCHNODE' ]; then
is_searchnode=true
elif [ "$install_type" = 'HEAVYNODE' ]; then
is_heavynode=true
elif [ "$install_type" = 'FLEET' ]; then
is_fleet=true
elif [ "$install_type" = 'IDH' ]; then
is_idh=true
elif [ "$install_type" = 'IMPORT' ]; then
is_import=true
elif [ "$install_type" = 'RECEIVER' ]; then
is_receiver=true
elif [ "$install_type" = 'DESKTOP' ]; then
is_desktop=true
fi
}
proxy_validate() {
info "Testing proxy..."
local test_url="https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS"
proxy_test_err=$(curl -sS "$test_url" --proxy "$so_proxy" --connect-timeout 5 2>&1) # set short connection timeout so user doesn't sit waiting for proxy test to timeout
local ret=$?
if [[ $ret != 0 ]]; then
error "Could not reach $test_url using proxy provided"
error "Received error: $proxy_test_err"
if [[ -n $TESTING ]]; then
error "Exiting setup"
kill -SIGINT "$(ps --pid $$ -oppid=)"; fail_setup
fi
fi
return $ret
}
reserve_group_ids() {
# This is a hack to fix OS from taking group IDs that we need
logCmd "groupadd -g 928 kratos"
logCmd "groupadd -g 930 elasticsearch"
logCmd "groupadd -g 931 logstash"
logCmd "groupadd -g 932 kibana"
logCmd "groupadd -g 933 elastalert"
logCmd "groupadd -g 937 zeek"
logCmd "groupadd -g 940 suricata"
logCmd "groupadd -g 941 stenographer"
logCmd "groupadd -g 945 ossec"
logCmd "groupadd -g 946 cyberchef"
}
reserve_ports() {
# These are also set via salt but need to be set pre-install to avoid conflicts before salt runs
if ! sysctl net.ipv4.ip_local_reserved_ports | grep 55000 | grep 57314; then
info "Reserving ephemeral ports used by Security Onion components to avoid collisions"
sysctl -w net.ipv4.ip_local_reserved_ports="55000,57314"
else
info "Ephemeral ports already reserved"
fi
}
reinstall_init() {
info "Putting system in state to run setup again"
if [[ $install_type =~ ^(MANAGER|EVAL|MANAGERSEARCH|STANDALONE|FLEET|IMPORT)$ ]]; then
local salt_services=( "salt-master" "salt-minion" )
else
local salt_services=( "salt-minion" )
fi
local service_retry_count=20
# Disregard previous install outcomes
rm -f /root/failure
rm -f /root/success
{
# remove all of root's cronjobs
logCmd "crontab -r -u root"
if command -v salt-call &> /dev/null && grep -q "master:" /etc/salt/minion 2> /dev/null; then
# Disable schedule so highstate doesn't start running during the install
salt-call -l info schedule.disable --local
# Kill any currently running salt jobs, also to prevent issues with highstate.
salt-call -l info saltutil.kill_all_jobs --local
fi
logCmd "salt-call state.apply ca.remove -linfo --local --file-root=../salt"
logCmd "salt-call state.apply ssl.remove -linfo --local --file-root=../salt"
# Kill any salt processes (safely)
for service in "${salt_services[@]}"; do
# Stop the service in the background so we can exit after a certain amount of time
if check_service_status "$service"; then
systemctl stop "$service" &
fi
local pid=$!
local count=0
while check_service_status "$service"; do
if [[ $count -gt $service_retry_count ]]; then
info "Could not stop $service after 1 minute, exiting setup."
# Stop the systemctl process trying to kill the service, show user a message, then exit setup
kill -9 $pid
fail_setup
fi
sleep 5
((count++))
done
done
# Remove all salt configs
rm -rf /etc/salt/engines/* /etc/salt/grains /etc/salt/master /etc/salt/master.d/* /etc/salt/minion /etc/salt/minion.d/* /etc/salt/pki/* /etc/salt/proxy /etc/salt/proxy.d/* /var/cache/salt/
if command -v docker &> /dev/null; then
# Stop and remove all so-* containers so files can be changed with more safety
if [[ $(docker ps -a -q --filter "name=so-" | wc -l) -gt 0 ]]; then
docker stop $(docker ps -a -q --filter "name=so-")
docker rm -f $(docker ps -a -q --filter "name=so-")
fi
fi
local date_string
date_string=$(date +%s)
# Backup /opt/so since we'll be rebuilding this directory during setup
backup_dir /opt/so "$date_string"
# If the elastic license has been accepted restore the state file
restore_file "/opt/so_old_$date_string/state/yeselastic.txt" "/opt/so/state/"
# Backup (and erase) directories in /nsm to prevent app errors
backup_dir /nsm/mysql "$date_string"
backup_dir /nsm/kratos "$date_string"
backup_dir /nsm/influxdb "$date_string"
# Uninstall local Elastic Agent, if installed
logCmd "elastic-agent uninstall -f"
if [[ $is_deb ]]; then
info "Unholding previously held packages."
apt-mark unhold $(apt-mark showhold)
fi
} >> "$setup_log" 2>&1
info "System reinstall init has been completed."
}
reset_proxy() {
[[ -f /etc/profile.d/so-proxy.sh ]] && rm -f /etc/profile.d/so-proxy.sh
[[ -f /etc/systemd/system/docker.service.d/http-proxy.conf ]] && rm -f /etc/systemd/system/docker.service.d/http-proxy.conf
systemctl daemon-reload
command -v docker &> /dev/null && info "Restarting Docker..." && logCmd "systemctl restart docker"
[[ -f /root/.docker/config.json ]] && rm -f /root/.docker/config.json
[[ -f /etc/gitconfig ]] && rm -f /etc/gitconfig
if [[ $is_rpm ]]; then
sed -i "/proxy=/d" /etc/dnf/dnf.conf
else
[[ -f /etc/apt/apt.conf.d/00-proxy.conf ]] && rm -f /etc/apt/apt.conf.d/00-proxy.conf
fi
}
restore_file() {
src=$1
dst=$2
if [ -f "$src" ]; then
[ ! -d "$dst" ] && mkdir -v -p "$dst"
info "Restoring $src to $dst."
cp -v "$src" "$dst" >> "$setup_log" 2>&1
fi
}
backup_dir() {
dir=$1
backup_suffix=$2
if [[ -d $dir ]]; then
mv "$dir" "${dir}_old_${backup_suffix}"
fi
}
drop_install_options() {
# Drop the install Variable
echo "MAINIP=$MAINIP" > /opt/so/install.txt
echo "MNIC=$MNIC" >> /opt/so/install.txt
echo "NODE_DESCRIPTION='$NODE_DESCRIPTION'" >> /opt/so/install.txt
echo "ES_HEAP_SIZE=$ES_HEAP_SIZE" >> /opt/so/install.txt
echo "PATCHSCHEDULENAME=$PATCHSCHEDULENAME" >> /opt/so/install.txt
echo "INTERFACE=$INTERFACE" >> /opt/so/install.txt
NODETYPE=${install_type^^}
echo "NODETYPE=$NODETYPE" >> /opt/so/install.txt
if [[ $low_mem == "true" ]]; then
echo "CORECOUNT=1" >> /opt/so/install.txt
else
echo "CORECOUNT=$lb_procs" >> /opt/so/install.txt
fi
echo "LSHOSTNAME=$HOSTNAME" >> /opt/so/install.txt
echo "LSHEAP=$LS_HEAP_SIZE" >> /opt/so/install.txt
echo "CPUCORES=$num_cpu_cores" >> /opt/so/install.txt
echo "IDH_MGTRESTRICT=$IDH_MGTRESTRICT" >> /opt/so/install.txt
echo "IDH_SERVICES=$IDH_SERVICES" >> /opt/so/install.txt
}
remove_package() {
local package_name=$1
if [[ $is_rpm ]]; then
if rpm -qa | grep -q "$package_name"; then
logCmd "dnf remove -y $package_name"
fi
else
if dpkg -l | grep -q "$package_name"; then
retry 150 10 "apt purge -y \"$package_name\""
fi
fi
}
# When updating the salt version, also update the version in securityonion-builds/images/iso-task/Dockerfile and salt/salt/master.defaults.yaml and salt/salt/minion.defaults.yaml
# CAUTION! SALT VERSION UDDATES - READ BELOW
# When updating the salt version, also update the version in:
# - securityonion-builds/iso-resources/build.sh
# - securityonion-builds/iso-resources/packages.lst
# - securityonion/salt/salt/master.defaults.yaml
# - securityonion/salt/salt/minion.defaults.yaml
securityonion_repo() {
# Remove all the current repos
if [[ $is_oracle ]]; then
logCmd "dnf -v clean all"
logCmd "mkdir -vp /root/oldrepos"
if [ -n "$(ls -A /etc/yum.repos.d/ 2>/dev/null)" ]; then
logCmd "mv -v /etc/yum.repos.d/* /root/oldrepos/"
fi
if ! $is_desktop_grid; then
gpg_rpm_import
if [[ ! $is_airgap ]]; then
echo "https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9" > /etc/yum/mirror.txt
echo "https://so-repo-east.s3.us-east-005.backblazeb2.com/prod/2.4/oracle/9" >> /etc/yum/mirror.txt
echo "[main]" > /etc/yum.repos.d/securityonion.repo
echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo
echo "installonly_limit=3" >> /etc/yum.repos.d/securityonion.repo
echo "clean_requirements_on_remove=True" >> /etc/yum.repos.d/securityonion.repo
echo "best=True" >> /etc/yum.repos.d/securityonion.repo
echo "skip_if_unavailable=False" >> /etc/yum.repos.d/securityonion.repo
echo "cachedir=/opt/so/conf/reposync/cache" >> /etc/yum.repos.d/securityonion.repo
echo "keepcache=0" >> /etc/yum.repos.d/securityonion.repo
echo "[securityonionsync]" >> /etc/yum.repos.d/securityonion.repo
echo "name=Security Onion Repo repo" >> /etc/yum.repos.d/securityonion.repo
echo "mirrorlist=file:///etc/yum/mirror.txt" >> /etc/yum.repos.d/securityonion.repo
echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo
echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo
logCmd "dnf repolist"
else
echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo
echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo
echo "baseurl=https://$MSRV/repo" >> /etc/yum.repos.d/securityonion.repo
echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo
echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo
echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo
logCmd "dnf repolist"
fi
elif [[ ! $waitforstate ]]; then
echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo
echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo
echo "baseurl=https://$MSRV/repo" >> /etc/yum.repos.d/securityonion.repo
echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo
echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo
echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo
elif [[ $waitforstate ]]; then
echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo
echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo
echo "baseurl=file:///nsm/repo/" >> /etc/yum.repos.d/securityonion.repo
echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo
echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo
fi
fi
if [[ $is_rpm ]]; then logCmd "dnf repolist all"; fi
if [[ $waitforstate ]]; then
if [[ $is_rpm ]]; then
# Build the repo locally so we can use it
echo "Syncing Repos"
repo_sync_local
fi
fi
}
repo_sync_local() {
SALTVERSION=$(egrep 'version: [0-9]{4}' ../salt/salt/master.defaults.yaml | sed 's/^.*version: //')
info "Repo Sync"
if [[ $is_supported ]]; then
# Sync the repo from the the SO repo locally.
# Check for reposync
info "Adding Repo Download Configuration"
mkdir -p /nsm/repo
mkdir -p /opt/so/conf/reposync/cache
echo "https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9" > /opt/so/conf/reposync/mirror.txt
echo "https://repo-alt.securityonion.net/prod/2.4/oracle/9" >> /opt/so/conf/reposync/mirror.txt
echo "[main]" > /opt/so/conf/reposync/repodownload.conf
echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf
echo "installonly_limit=3" >> /opt/so/conf/reposync/repodownload.conf
echo "clean_requirements_on_remove=True" >> /opt/so/conf/reposync/repodownload.conf
echo "best=True" >> /opt/so/conf/reposync/repodownload.conf
echo "skip_if_unavailable=False" >> /opt/so/conf/reposync/repodownload.conf
echo "cachedir=/opt/so/conf/reposync/cache" >> /opt/so/conf/reposync/repodownload.conf
echo "keepcache=0" >> /opt/so/conf/reposync/repodownload.conf
echo "[securityonionsync]" >> /opt/so/conf/reposync/repodownload.conf
echo "name=Security Onion Repo repo" >> /opt/so/conf/reposync/repodownload.conf
echo "mirrorlist=file:///opt/so/conf/reposync/mirror.txt" >> /opt/so/conf/reposync/repodownload.conf
echo "enabled=1" >> /opt/so/conf/reposync/repodownload.conf
echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf
logCmd "dnf repolist"
if [[ ! $is_airgap ]]; then
curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install
retry 5 60 "dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionsync --download-metadata -p /nsm/repo/" >> "$setup_log" 2>&1 || fail_setup
# After the download is complete run createrepo
create_repo
fi
else
# Add the proper repos for unsupported stuff
echo "Adding Repos"
if [[ $is_rpm ]]; then
if [[ $is_rhel ]]; then
logCmd "subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms"
info "Install epel for rhel"
logCmd "dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm"
logCmd "dnf -y install https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm"
else
logCmd "dnf config-manager --set-enabled crb"
logCmd "dnf -y install epel-release"
fi
dnf install -y yum-utils device-mapper-persistent-data lvm2
curl -fsSL https://repo.securityonion.net/file/so-repo/prod/2.4/so/so.repo | tee /etc/yum.repos.d/so.repo
rpm --import https://repo.saltproject.io/salt/py3/redhat/9/x86_64/SALT-PROJECT-GPG-PUBKEY-2023.pub
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
curl -fsSL "https://repo.saltproject.io/salt/py3/redhat/9/x86_64/minor/$SALTVERSION.repo" | tee /etc/yum.repos.d/salt.repo
dnf repolist
curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install
else
echo "Not sure how you got here."
exit 1
fi
fi
}
saltify() {
info "Installing Salt"
SALTVERSION=$(egrep 'version: [0-9]{4}' ../salt/salt/master.defaults.yaml | sed 's/^.*version: //')
if [[ $is_deb ]]; then
DEBIAN_FRONTEND=noninteractive retry 150 20 "apt-get -y -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" upgrade" >> "$setup_log" 2>&1 || fail_setup
if [ $OSVER == "focal" ]; then update-alternatives --install /usr/bin/python python /usr/bin/python3.10 10; fi
local pkg_arr=(
'apache2-utils'
'ca-certificates'
'curl'
'software-properties-common'
'apt-transport-https'
'openssl'
'netcat-openbsd'
'jq'
'gnupg'
)
retry 150 20 "apt-get -y install ${pkg_arr[*]}" || fail_setup
logCmd "mkdir -vp /etc/apt/keyrings"
logCmd "wget -q --inet4-only -O /etc/apt/keyrings/docker.pub https://download.docker.com/linux/ubuntu/gpg"
if [[ $is_ubuntu ]]; then
# Add Salt Repo
logCmd "curl -fsSL -o /etc/apt/keyrings/salt-archive-keyring-2023.gpg https://repo.saltproject.io/salt/py3/ubuntu/$UBVER/amd64/minor/$SALTVERSION/SALT-PROJECT-GPG-PUBKEY-2023.gpg"
echo "deb [signed-by=/etc/apt/keyrings/salt-archive-keyring-2023.gpg] https://repo.saltproject.io/salt/py3/ubuntu/$UBVER/amd64/minor/$SALTVERSION/ $OSVER main" | sudo tee /etc/apt/sources.list.d/salt.list
# Add Docker Repo
add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
else
# Add Salt Repo *NOTE* You have to use debian 11 since it isn't out for 12
logCmd "curl -fsSL -o /etc/apt/keyrings/salt-archive-keyring-2023.gpg https://repo.saltproject.io/salt/py3/debian/11/amd64/minor/$SALTVERSION/SALT-PROJECT-GPG-PUBKEY-2023.gpg"
echo "deb [signed-by=/etc/apt/keyrings/salt-archive-keyring-2023.gpg] https://repo.saltproject.io/salt/py3/debian/11/amd64/minor/$SALTVERSION/ bullseye main" | sudo tee /etc/apt/sources.list.d/salt.list
# Add Docker Repo
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $OSVER stable" > /etc/apt/sources.list.d/docker.list
fi
logCmd "apt-key add /etc/apt/keyrings/salt-archive-keyring-2023.gpg"
#logCmd "apt-key add /opt/so/gpg/SALTSTACK-GPG-KEY.pub"
logCmd "apt-key add /etc/apt/keyrings/docker.pub"
# Add SO Saltstack Repo
#echo "deb https://repo.securityonion.net/file/securityonion-repo/ubuntu/20.04/amd64/salt3004.2/ focal main" > /etc/apt/sources.list.d/saltstack.list
# Ain't nothing but a GPG
retry 150 20 "apt-get update" "" "Err:" || fail_setup
if [[ $waitforstate ]]; then
retry 150 20 "apt-get -y install salt-common=$SALTVERSION salt-minion=$SALTVERSION salt-master=$SALTVERSION" || fail_setup
retry 150 20 "apt-mark hold salt-minion salt-common salt-master" || fail_setup
retry 150 20 "apt-get -y install python3-pip python3-dateutil python3-m2crypto python3-packaging python3-influxdb python3-lxml" || exit 1
else
retry 150 20 "apt-get -y install salt-common=$SALTVERSION salt-minion=$SALTVERSION" || fail_setup
retry 150 20 "apt-mark hold salt-minion salt-common" || fail_setup
fi
fi
if [[ $is_rpm ]]; then
if [[ $waitforstate ]]; then
# install all for a manager
logCmd "dnf -y install salt-$SALTVERSION salt-master-$SALTVERSION salt-minion-$SALTVERSION"
else
# We just need the minion
if [[ $is_airgap ]]; then
logCmd "dnf -y install salt salt-minion"
else
logCmd "dnf -y install salt-$SALTVERSION salt-minion-$SALTVERSION"
fi
fi
fi
logCmd "mkdir -p /etc/salt/minion.d"
salt_install_module_deps
salt_patch_x509_v2
}
salt_install_module_deps() {
logCmd "salt-call state.apply salt.python_modules --local --file-root=../salt/"
}
salt_patch_x509_v2() {
# this can be removed when https://github.com/saltstack/salt/issues/64195 is resolved
if [ $SALTVERSION == "3006.1" ]; then
info "Salt version 3006.1 found. Patching /opt/saltstack/salt/lib/python3.10/site-packages/salt/states/x509_v2.py"
\cp -v ./files/patch/states/x509_v2.py /opt/saltstack/salt/lib/python3.10/site-packages/salt/states/x509_v2.py
fi
}
# Create an secrets pillar so that passwords survive re-install
secrets_pillar(){
if [ ! -f $local_salt_dir/pillar/secrets.sls ]; then
info "Creating Secrets Pillar"
mkdir -p $local_salt_dir/pillar
printf '%s\n'\
"secrets:"\
" import_pass: $IMPORTPASS"\
" influx_pass: $INFLUXPASS" > $local_salt_dir/pillar/secrets.sls
fi
}
set_network_dev_status_list() {
readarray -t nmcli_dev_status_list <<< "$(nmcli -t -f DEVICE,STATE -c no dev status)"
export nmcli_dev_status_list
}
set_main_ip() {
local count=0
local progress='.'
local c=0
local m=3.3
local max_attempts=30
info "Gathering the management IP. "
while ! valid_ip4 "$MAINIP" || ! valid_ip4 "$MNIC_IP"; do
MAINIP=$(ip route get 1 | awk '{print $7;exit}')
MNIC_IP=$(ip a s "$MNIC" | grep -oE 'inet [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d' ' -f2)
((count=count+1))
p=$(awk -vp=$m -vq=$count 'BEGIN{printf "%.0f" ,p * q}')
printf "%-*s" $((count+1)) '[' | tr ' ' '#'
printf "%*s%3d%%\r" $((max_attempts-count)) "]" "$p"
if [ $count = $max_attempts ]; then
info "ERROR: Could not determine MAINIP or MNIC_IP."
info "MAINIP=$MAINIP"
info "MNIC_IP=$MNIC_IP"
whiptail_error_message "The management IP could not be determined. Please check the log at /root/sosetup.log and verify the network configuration. Select OK to exit."
fail_setup
fi
sleep 1
done
}
# Add /usr/sbin to everyone's path
set_path() {
echo "complete -cf sudo" >> /etc/profile.d/securityonion.sh
}
set_minion_info() {
short_name=$(echo "$HOSTNAME" | awk -F. '{print $1}')
if [[ $is_desktop ]]; then
MINION_ID=$(echo "${short_name}_desktop" | tr '[:upper:]' '[:lower:]')
fi
if [[ ! $is_desktop ]]; then
MINION_ID=$(echo "${short_name}_${install_type}" | tr '[:upper:]' '[:lower:]')
fi
export MINION_ID
info "MINION_ID = $MINION_ID"
minion_type=$(get_minion_type)
}
set_proxy() {
# Don't proxy localhost, local ip, and management ip
no_proxy_string="localhost, 127.0.0.1, ${MAINIP}, ${HOSTNAME}"
if [[ -n $MSRV ]] && [[ -n $MSRVIP ]];then
no_proxy_string="${no_proxy_string}, ${MSRVIP}, ${MSRV}"
fi
# Set proxy environment variables used by curl, wget, docker, and others
{
echo "export use_proxy=on"
echo "export http_proxy=\"${so_proxy}\""
echo "export https_proxy=\"\$http_proxy\""
echo "export ftp_proxy=\"\$http_proxy\""
echo "export no_proxy=\"${no_proxy_string}\""
} > /etc/profile.d/so-proxy.sh
source /etc/profile.d/so-proxy.sh
[[ -d '/etc/systemd/system/docker.service.d' ]] || mkdir -p /etc/systemd/system/docker.service.d
# Create proxy config for dockerd
printf '%s\n'\
"[Service]"\
"Environment=\"HTTP_PROXY=${so_proxy}\""\
"Environment=\"HTTPS_PROXY=${so_proxy}\""\
"Environment=\"NO_PROXY=${no_proxy_string}\"" > /etc/systemd/system/docker.service.d/http-proxy.conf
systemctl daemon-reload
command -v docker &> /dev/null && systemctl restart docker
# Create config.json for docker containers
[[ -d /root/.docker ]] || mkdir /root/.docker
printf '%s\n'\
"{"\
" \"proxies\":"\
" {"\
" \"default\":"\
" {"\
" \"httpProxy\":\"${so_proxy}\","\
" \"httpsProxy\":\"${so_proxy}\","\
" \"ftpProxy\":\"${so_proxy}\","\
" \"noProxy\":\"${no_proxy_string}\""\
" }"\
" }"\
"}" > /root/.docker/config.json
# Set proxy for package manager
if [[ $is_rpm ]]; then
echo "proxy=$so_proxy" >> /etc/yum.conf
else
# Set it up so the updates roll through the manager
printf '%s\n'\
"Acquire::http::Proxy \"$so_proxy\";"\
"Acquire::https::Proxy \"$so_proxy\";" > /etc/apt/apt.conf.d/00-proxy.conf
fi
# Set global git proxy
printf '%s\n'\
"[http]"\
" proxy = ${so_proxy}" > /etc/gitconfig
}
setup_salt_master_dirs() {
# Create salt master directories
mkdir -p $default_salt_dir/pillar
mkdir -p $default_salt_dir/salt
mkdir -p $local_salt_dir/pillar
mkdir -p $local_salt_dir/salt
# Copy over the salt code and templates
if [ "$setup_type" = 'iso' ]; then
logCmd "rsync -avh --exclude 'TRANS.TBL' /home/$INSTALLUSERNAME/SecurityOnion/pillar/* $default_salt_dir/pillar/"
logCmd "rsync -avh --exclude 'TRANS.TBL' /home/$INSTALLUSERNAME/SecurityOnion/salt/* $default_salt_dir/salt/"
logCmd "mkdir -p $local_salt_dir/salt/zeek/policy/intel"
logCmd "touch $local_salt_dir/salt/zeek/policy/intel/intel.dat"
else
logCmd "cp -Rv ../pillar/* $default_salt_dir/pillar/"
logCmd "cp -Rv ../salt/* $default_salt_dir/salt/"
logCmd "mkdir -p $local_salt_dir/salt/zeek/policy/intel"
logCmd "touch $local_salt_dir/salt/zeek/policy/intel/intel.dat"
fi
info "Chown the salt dirs on the manager for socore"
logCmd "chown -R socore:socore /opt/so"
}
set_progress_str() {
local percentage_input=$1
progress_bar_text=$2
export progress_bar_text
local nolog=$2
if (( "$percentage_input" >= "$percentage" )); then
percentage="$percentage_input"
fi
percentage_str="XXX\n${percentage}\n${progress_bar_text}\nXXX"
echo -e "$percentage_str"
if [[ -z $nolog ]]; then
info "Progressing ($percentage%): $progress_bar_text"
# printf '%s\n' \
# '----'\
# "$percentage% - ${progress_bar_text^^}"\
# "----" >> "$setup_log" 2>&1
fi
}
set_default_log_size() {
local percentage
case $install_type in
STANDALONE | EVAL | HEAVYNODE)
percentage=50
;;
*)
percentage=80
;;
esac
local disk_dir="/"
if mountpoint -q /nsm; then
disk_dir="/nsm"
fi
if mountpoint -q /nsm/elasticsearch; then
disk_dir="/nsm/elasticsearch"
percentage=80
fi
local disk_size_1k
disk_size_1k=$(df $disk_dir | grep -v "^Filesystem" | awk '{print $2}')
local ratio="1048576"
local disk_size_gb
disk_size_gb=$( echo "$disk_size_1k" "$ratio" | awk '{print($1/$2)}' )
log_size_limit=$( echo "$disk_size_gb" "$percentage" | awk '{printf("%.0f", $1 * ($2/100))}')
}
set_desktop_background() {
logCmd "mkdir /usr/local/share/backgrounds"
logCmd "cp ../salt/desktop/files/so-wallpaper.jpg /usr/local/share/backgrounds/so-wallpaper.jpg"
logCmd "cp ../salt/desktop/files/00-background /etc/dconf/db/local.d/00-background"
logCmd "dconf update"
}
set_hostname() {
logCmd "hostnamectl set-hostname --static $HOSTNAME"
echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts
echo "::1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts
echo "$HOSTNAME" > /etc/hostname
logCmd "hostname -F /etc/hostname"
}
set_initial_firewall_policy() {
case "$install_type" in
'EVAL' | 'MANAGER' | 'MANAGERSEARCH' | 'STANDALONE' | 'IMPORT')
so-firewall includehost $minion_type $MAINIP --apply
;;
esac
}
set_initial_firewall_access() {
if [[ ! -z "$ALLOW_CIDR" ]]; then
so-firewall includehost analyst $ALLOW_CIDR --apply
fi
if [[ ! -z "$MINION_CIDR" ]]; then
so-firewall includehost sensor $MINION_CIDR
so-firewall includehost searchnode $MINION_CIDR --apply
fi
}
# Set up the management interface on the ISO
set_management_interface() {
title "Setting up the main interface"
if [ "$address_type" = 'DHCP' ]; then
logCmd "nmcli con mod $MNIC connection.autoconnect yes"
logCmd "nmcli con up $MNIC"
logCmd "nmcli -p connection show $MNIC"
else
# Set Static IP
nmcli con mod "$MNIC" ipv4.addresses "$MIP"/"$MMASK"\
ipv4.gateway "$MGATEWAY" \
ipv4.dns "$MDNS"\
ipv4.dns-search "$MSEARCH"\
connection.autoconnect yes\
ipv4.method manual >> "$setup_log" 2>&1
nmcli con up "$MNIC" >> "$setup_log" 2>&1
fi
}
set_redirect() {
title "Setting redirect host"
case $REDIRECTINFO in
'IP')
REDIRECTIT="$MAINIP"
;;
'HOSTNAME')
REDIRECTIT="$HOSTNAME"
;;
*)
REDIRECTIT="$REDIRECTHOST"
;;
esac
}
set_timezone() {
logCmd "timedatectl set-timezone Etc/UTC"
}
so_add_user() {
local username=$1
local uid=$2
local gid=$3
local home_dir=$4
if [ "$5" ]; then local pass=$5; fi
info "Add $username user"
logCmd "groupadd --gid $gid $username"
logCmd "useradd -m --uid $uid --gid $gid --home-dir $home_dir $username"
# If a password has been passed in, set the password
if [ "$pass" ]; then
echo "$username":"$pass" | chpasswd --crypt-method=SHA512
fi
}
update_sudoers_for_testing() {
if [ -n "$TESTING" ]; then
info "Ensuring $INSTALLUSERNAME has password-less sudo access for automated testing purposes."
sed -i "s/^$INSTALLUSERNAME ALL=(ALL) ALL/$INSTALLUSERNAME ALL=(ALL) NOPASSWD: ALL/" /etc/sudoers
fi
}
update_packages() {
if [[ $is_oracle ]]; then
logCmd "dnf repolist"
logCmd "dnf -y update --allowerasing --exclude=salt*,docker*,containerd*"
RMREPOFILES=("oracle-linux-ol9.repo" "uek-ol9.repo" "virt-ol9.repo")
info "Removing repo files added by oracle-repos package update"
for FILE in ${RMREPOFILES[@]}; do
logCmd "rm -f /etc/yum.repos.d/$FILE"
done
elif [[ $is_deb ]]; then
info "Running apt-get update"
retry 150 10 "apt-get -y update" "" "Err:" >> "$setup_log" 2>&1 || fail_setup
info "Running apt-get upgrade"
retry 150 10 "apt-get -y upgrade" >> "$setup_log" 2>&1 || fail_setup
fi
}
# This is used for development to speed up network install tests.
use_turbo_proxy() {
if [[ ! $install_type =~ ^(MANAGER|EVAL|HELIXSENSOR|MANAGERSEARCH|STANDALONE)$ ]]; then
info "turbo is not supported on this install type"
return
fi
if [[ $OS == 'centos' ]]; then
printf '%s\n' "proxy=${TURBO}:3142" >> /etc/yum.conf
else
printf '%s\n'\
"Acquire {"\
" HTTP::proxy \"${TURBO}:3142\";"\
" HTTPS::proxy \"${TURBO}:3142\";"\
"}" > /etc/apt/apt.conf.d/proxy.conf
fi
}
wait_for_file() {
local filename=$1
local max_attempts=$2 # this is multiplied by the wait interval, so make sure it isn't too large
local cur_attempts=0
local wait_interval=$3
local total_time=$(( max_attempts * wait_interval ))
local date
date=$(date)
while [[ $cur_attempts -lt $max_attempts ]]; do
if [ -f "$filename" ]; then
info "File $filename found at $date"
return 0
else
((cur_attempts++))
info "File $filename does not exist; waiting ${wait_interval}s then checking again ($cur_attempts/$max_attempts)..."
sleep "$wait_interval"
fi
done
info "Could not find $filename after waiting ${total_time}s"
return 1
}
verify_setup() {
info "Verifying setup"
set -o pipefail
./so-verify "$setup_type" 2>&1 | tee -a $setup_log
result=$?
set +o pipefail
if [[ $result -eq 0 ]]; then
# Remove ISO sudoers entry if present
sed -i '/so-setup/d' /etc/sudoers
whiptail_setup_complete
else
whiptail_setup_failed
fi
}