mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-04-16 01:32:07 +02:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f9da893ac | ||
|
|
cefbe01333 | ||
|
|
0d3e2a0708 | ||
|
|
9ccd0acb4f | ||
|
|
e339aa41d5 | ||
|
|
1ffdcab3be | ||
|
|
01a24b3684 | ||
|
|
da1045e052 | ||
|
|
f1cdd265f9 | ||
|
|
55be1f1119 | ||
|
|
631f5bd754 | ||
|
|
c1b1452bd9 | ||
|
|
fb4615d5cd | ||
|
|
2dfa83dd7d | ||
|
|
6eaf22fc5a | ||
|
|
b87af8ea3d | ||
|
|
592a6a4c21 | ||
|
|
46e38d39bb | ||
|
|
409d4fb632 | ||
|
|
61bdfb1a4b | ||
|
|
9d72149fcd | ||
|
|
358a2e6d3f | ||
|
|
762e73faf5 | ||
|
|
e6afecbaa9 | ||
|
|
868cd11874 | ||
|
|
88de246ce3 | ||
|
|
3643b57167 | ||
|
|
5b3ca98b80 | ||
|
|
76f4ccf8c8 | ||
|
|
3dec6986b6 | ||
|
|
ff45e5ebc6 | ||
|
|
1e2b51eae6 | ||
|
|
58d332ea94 |
1
.github/DISCUSSION_TEMPLATE/3-0.yml
vendored
1
.github/DISCUSSION_TEMPLATE/3-0.yml
vendored
@@ -10,6 +10,7 @@ body:
|
|||||||
options:
|
options:
|
||||||
-
|
-
|
||||||
- 3.0.0
|
- 3.0.0
|
||||||
|
- 3.1.0
|
||||||
- Other (please provide detail below)
|
- Other (please provide detail below)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ base:
|
|||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
- elasticsearch.auth
|
- elasticsearch.auth
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/postgres/auth.sls') %}
|
||||||
|
- postgres.auth
|
||||||
|
{% endif %}
|
||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
- kibana.secrets
|
- kibana.secrets
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -60,6 +63,8 @@ base:
|
|||||||
- redis.adv_redis
|
- redis.adv_redis
|
||||||
- influxdb.soc_influxdb
|
- influxdb.soc_influxdb
|
||||||
- influxdb.adv_influxdb
|
- influxdb.adv_influxdb
|
||||||
|
- postgres.soc_postgres
|
||||||
|
- postgres.adv_postgres
|
||||||
- elasticsearch.nodes
|
- elasticsearch.nodes
|
||||||
- elasticsearch.soc_elasticsearch
|
- elasticsearch.soc_elasticsearch
|
||||||
- elasticsearch.adv_elasticsearch
|
- elasticsearch.adv_elasticsearch
|
||||||
@@ -101,6 +106,9 @@ base:
|
|||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
- elasticsearch.auth
|
- elasticsearch.auth
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/postgres/auth.sls') %}
|
||||||
|
- postgres.auth
|
||||||
|
{% endif %}
|
||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
- kibana.secrets
|
- kibana.secrets
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -126,6 +134,8 @@ base:
|
|||||||
- redis.adv_redis
|
- redis.adv_redis
|
||||||
- influxdb.soc_influxdb
|
- influxdb.soc_influxdb
|
||||||
- influxdb.adv_influxdb
|
- influxdb.adv_influxdb
|
||||||
|
- postgres.soc_postgres
|
||||||
|
- postgres.adv_postgres
|
||||||
- backup.soc_backup
|
- backup.soc_backup
|
||||||
- backup.adv_backup
|
- backup.adv_backup
|
||||||
- zeek.soc_zeek
|
- zeek.soc_zeek
|
||||||
@@ -146,6 +156,9 @@ base:
|
|||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
- elasticsearch.auth
|
- elasticsearch.auth
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/postgres/auth.sls') %}
|
||||||
|
- postgres.auth
|
||||||
|
{% endif %}
|
||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
- kibana.secrets
|
- kibana.secrets
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -160,6 +173,8 @@ base:
|
|||||||
- redis.adv_redis
|
- redis.adv_redis
|
||||||
- influxdb.soc_influxdb
|
- influxdb.soc_influxdb
|
||||||
- influxdb.adv_influxdb
|
- influxdb.adv_influxdb
|
||||||
|
- postgres.soc_postgres
|
||||||
|
- postgres.adv_postgres
|
||||||
- elasticsearch.nodes
|
- elasticsearch.nodes
|
||||||
- elasticsearch.soc_elasticsearch
|
- elasticsearch.soc_elasticsearch
|
||||||
- elasticsearch.adv_elasticsearch
|
- elasticsearch.adv_elasticsearch
|
||||||
@@ -260,6 +275,9 @@ base:
|
|||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
- elasticsearch.auth
|
- elasticsearch.auth
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/postgres/auth.sls') %}
|
||||||
|
- postgres.auth
|
||||||
|
{% endif %}
|
||||||
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
- kibana.secrets
|
- kibana.secrets
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -285,6 +303,8 @@ base:
|
|||||||
- redis.adv_redis
|
- redis.adv_redis
|
||||||
- influxdb.soc_influxdb
|
- influxdb.soc_influxdb
|
||||||
- influxdb.adv_influxdb
|
- influxdb.adv_influxdb
|
||||||
|
- postgres.soc_postgres
|
||||||
|
- postgres.adv_postgres
|
||||||
- zeek.soc_zeek
|
- zeek.soc_zeek
|
||||||
- zeek.adv_zeek
|
- zeek.adv_zeek
|
||||||
- bpf.soc_bpf
|
- bpf.soc_bpf
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
'manager',
|
'manager',
|
||||||
'nginx',
|
'nginx',
|
||||||
'influxdb',
|
'influxdb',
|
||||||
|
'postgres',
|
||||||
|
'postgres.auth',
|
||||||
'soc',
|
'soc',
|
||||||
'kratos',
|
'kratos',
|
||||||
'hydra',
|
'hydra',
|
||||||
|
|||||||
@@ -32,3 +32,23 @@ so_config_backup:
|
|||||||
- daymonth: '*'
|
- daymonth: '*'
|
||||||
- month: '*'
|
- month: '*'
|
||||||
- dayweek: '*'
|
- dayweek: '*'
|
||||||
|
|
||||||
|
postgres_backup_script:
|
||||||
|
file.managed:
|
||||||
|
- name: /usr/sbin/so-postgres-backup
|
||||||
|
- user: root
|
||||||
|
- group: root
|
||||||
|
- mode: 755
|
||||||
|
- source: salt://backup/tools/sbin/so-postgres-backup
|
||||||
|
|
||||||
|
# Add postgres database backup
|
||||||
|
so_postgres_backup:
|
||||||
|
cron.present:
|
||||||
|
- name: /usr/sbin/so-postgres-backup > /dev/null 2>&1
|
||||||
|
- identifier: so_postgres_backup
|
||||||
|
- user: root
|
||||||
|
- minute: '5'
|
||||||
|
- hour: '0'
|
||||||
|
- daymonth: '*'
|
||||||
|
- month: '*'
|
||||||
|
- dayweek: '*'
|
||||||
|
|||||||
36
salt/backup/tools/sbin/so-postgres-backup
Normal file
36
salt/backup/tools/sbin/so-postgres-backup
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
TODAY=$(date '+%Y_%m_%d')
|
||||||
|
BACKUPDIR=/nsm/backup
|
||||||
|
BACKUPFILE="$BACKUPDIR/so-postgres-backup-$TODAY.sql.gz"
|
||||||
|
MAXBACKUPS=7
|
||||||
|
|
||||||
|
mkdir -p $BACKUPDIR
|
||||||
|
|
||||||
|
# Skip if already backed up today
|
||||||
|
if [ -f "$BACKUPFILE" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skip if container isn't running
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -q '^so-postgres$'; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dump all databases and roles, compress
|
||||||
|
docker exec so-postgres pg_dumpall -U postgres | gzip > "$BACKUPFILE"
|
||||||
|
|
||||||
|
# Retention cleanup
|
||||||
|
NUMBACKUPS=$(find $BACKUPDIR -type f -name "so-postgres-backup*" | wc -l)
|
||||||
|
while [ "$NUMBACKUPS" -gt "$MAXBACKUPS" ]; do
|
||||||
|
OLDEST=$(find $BACKUPDIR -type f -name "so-postgres-backup*" -printf '%T+ %p\n' | sort | head -n 1 | awk -F" " '{print $2}')
|
||||||
|
rm -f "$OLDEST"
|
||||||
|
NUMBACKUPS=$(find $BACKUPDIR -type f -name "so-postgres-backup*" | wc -l)
|
||||||
|
done
|
||||||
@@ -54,6 +54,20 @@ x509_signing_policies:
|
|||||||
- extendedKeyUsage: serverAuth
|
- extendedKeyUsage: serverAuth
|
||||||
- days_valid: 820
|
- days_valid: 820
|
||||||
- copypath: /etc/pki/issued_certs/
|
- copypath: /etc/pki/issued_certs/
|
||||||
|
postgres:
|
||||||
|
- minions: '*'
|
||||||
|
- signing_private_key: /etc/pki/ca.key
|
||||||
|
- signing_cert: /etc/pki/ca.crt
|
||||||
|
- C: US
|
||||||
|
- ST: Utah
|
||||||
|
- L: Salt Lake City
|
||||||
|
- basicConstraints: "critical CA:false"
|
||||||
|
- keyUsage: "critical keyEncipherment"
|
||||||
|
- subjectKeyIdentifier: hash
|
||||||
|
- authorityKeyIdentifier: keyid,issuer:always
|
||||||
|
- extendedKeyUsage: serverAuth
|
||||||
|
- days_valid: 820
|
||||||
|
- copypath: /etc/pki/issued_certs/
|
||||||
elasticfleet:
|
elasticfleet:
|
||||||
- minions: '*'
|
- minions: '*'
|
||||||
- signing_private_key: /etc/pki/ca.key
|
- signing_private_key: /etc/pki/ca.key
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ container_list() {
|
|||||||
"so-hydra"
|
"so-hydra"
|
||||||
"so-nginx"
|
"so-nginx"
|
||||||
"so-pcaptools"
|
"so-pcaptools"
|
||||||
|
"so-postgres"
|
||||||
"so-soc"
|
"so-soc"
|
||||||
"so-suricata"
|
"so-suricata"
|
||||||
"so-telegraf"
|
"so-telegraf"
|
||||||
@@ -55,6 +56,7 @@ container_list() {
|
|||||||
"so-logstash"
|
"so-logstash"
|
||||||
"so-nginx"
|
"so-nginx"
|
||||||
"so-pcaptools"
|
"so-pcaptools"
|
||||||
|
"so-postgres"
|
||||||
"so-redis"
|
"so-redis"
|
||||||
"so-soc"
|
"so-soc"
|
||||||
"so-strelka-backend"
|
"so-strelka-backend"
|
||||||
|
|||||||
@@ -237,3 +237,11 @@ docker:
|
|||||||
extra_hosts: []
|
extra_hosts: []
|
||||||
extra_env: []
|
extra_env: []
|
||||||
ulimits: []
|
ulimits: []
|
||||||
|
'so-postgres':
|
||||||
|
final_octet: 89
|
||||||
|
port_bindings:
|
||||||
|
- 0.0.0.0:5432:5432
|
||||||
|
custom_bind_mounts: []
|
||||||
|
extra_hosts: []
|
||||||
|
extra_env: []
|
||||||
|
ulimits: []
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
'so-kratos',
|
'so-kratos',
|
||||||
'so-hydra',
|
'so-hydra',
|
||||||
'so-nginx',
|
'so-nginx',
|
||||||
|
'so-postgres',
|
||||||
'so-redis',
|
'so-redis',
|
||||||
'so-soc',
|
'so-soc',
|
||||||
'so-strelka-coordinator',
|
'so-strelka-coordinator',
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
'so-hydra',
|
'so-hydra',
|
||||||
'so-logstash',
|
'so-logstash',
|
||||||
'so-nginx',
|
'so-nginx',
|
||||||
|
'so-postgres',
|
||||||
'so-redis',
|
'so-redis',
|
||||||
'so-soc',
|
'so-soc',
|
||||||
'so-strelka-coordinator',
|
'so-strelka-coordinator',
|
||||||
@@ -77,6 +79,7 @@
|
|||||||
'so-kratos',
|
'so-kratos',
|
||||||
'so-hydra',
|
'so-hydra',
|
||||||
'so-nginx',
|
'so-nginx',
|
||||||
|
'so-postgres',
|
||||||
'so-soc'
|
'so-soc'
|
||||||
] %}
|
] %}
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ firewall:
|
|||||||
tcp:
|
tcp:
|
||||||
- 8086
|
- 8086
|
||||||
udp: []
|
udp: []
|
||||||
|
postgres:
|
||||||
|
tcp:
|
||||||
|
- 5432
|
||||||
|
udp: []
|
||||||
kafka_controller:
|
kafka_controller:
|
||||||
tcp:
|
tcp:
|
||||||
- 9093
|
- 9093
|
||||||
@@ -193,6 +197,7 @@ firewall:
|
|||||||
- kibana
|
- kibana
|
||||||
- redis
|
- redis
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- elasticsearch_rest
|
- elasticsearch_rest
|
||||||
- elasticsearch_node
|
- elasticsearch_node
|
||||||
- localrules
|
- localrules
|
||||||
@@ -379,6 +384,7 @@ firewall:
|
|||||||
- kibana
|
- kibana
|
||||||
- redis
|
- redis
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- elasticsearch_rest
|
- elasticsearch_rest
|
||||||
- elasticsearch_node
|
- elasticsearch_node
|
||||||
- docker_registry
|
- docker_registry
|
||||||
@@ -590,6 +596,7 @@ firewall:
|
|||||||
- kibana
|
- kibana
|
||||||
- redis
|
- redis
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- elasticsearch_rest
|
- elasticsearch_rest
|
||||||
- elasticsearch_node
|
- elasticsearch_node
|
||||||
- docker_registry
|
- docker_registry
|
||||||
@@ -799,6 +806,7 @@ firewall:
|
|||||||
- kibana
|
- kibana
|
||||||
- redis
|
- redis
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- elasticsearch_rest
|
- elasticsearch_rest
|
||||||
- elasticsearch_node
|
- elasticsearch_node
|
||||||
- docker_registry
|
- docker_registry
|
||||||
@@ -1011,6 +1019,7 @@ firewall:
|
|||||||
- kibana
|
- kibana
|
||||||
- redis
|
- redis
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- elasticsearch_rest
|
- elasticsearch_rest
|
||||||
- elasticsearch_node
|
- elasticsearch_node
|
||||||
- docker_registry
|
- docker_registry
|
||||||
|
|||||||
@@ -55,4 +55,16 @@
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{# Open Postgres (5432) to minion hostgroups when Telegraf is configured to write to Postgres #}
|
||||||
|
{% set TG_OUT = (GLOBALS.telegraf_output | default('INFLUXDB')) | upper %}
|
||||||
|
{% if TG_OUT in ['POSTGRES', 'BOTH'] %}
|
||||||
|
{% if role.startswith('manager') or role == 'standalone' or role == 'eval' %}
|
||||||
|
{% for r in ['sensor', 'searchnode', 'heavynode', 'receiver', 'fleet', 'idh', 'desktop', 'import'] %}
|
||||||
|
{% if FIREWALL_DEFAULT.firewall.role[role].chain["DOCKER-USER"].hostgroups[r] is defined %}
|
||||||
|
{% do FIREWALL_DEFAULT.firewall.role[role].chain["DOCKER-USER"].hostgroups[r].portgroups.append('postgres') %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% set FIREWALL_MERGED = salt['pillar.get']('firewall', FIREWALL_DEFAULT.firewall, merge=True) %}
|
{% set FIREWALL_MERGED = salt['pillar.get']('firewall', FIREWALL_DEFAULT.firewall, merge=True) %}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
global:
|
global:
|
||||||
pcapengine: SURICATA
|
pcapengine: SURICATA
|
||||||
pipeline: REDIS
|
pipeline: REDIS
|
||||||
|
telegraf_output: BOTH
|
||||||
@@ -65,4 +65,15 @@ global:
|
|||||||
description: Allows use of Endgame with Security Onion. This feature requires a license from Endgame.
|
description: Allows use of Endgame with Security Onion. This feature requires a license from Endgame.
|
||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
|
telegraf_output:
|
||||||
|
description: Selects the backend(s) Telegraf writes metrics to. INFLUXDB keeps the current behavior; POSTGRES writes to the grid's Postgres instance; BOTH dual-writes for migration validation.
|
||||||
|
regex: ^(INFLUXDB|POSTGRES|BOTH)$
|
||||||
|
options:
|
||||||
|
- INFLUXDB
|
||||||
|
- POSTGRES
|
||||||
|
- BOTH
|
||||||
|
regexFailureMessage: You must enter INFLUXDB, POSTGRES, or BOTH.
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
helpLink: influxdb
|
||||||
|
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ preupgrade_changes() {
|
|||||||
echo "Checking to see if changes are needed."
|
echo "Checking to see if changes are needed."
|
||||||
|
|
||||||
[[ "$INSTALLEDVERSION" =~ ^2\.4\.21[0-9]+$ ]] && up_to_3.0.0
|
[[ "$INSTALLEDVERSION" =~ ^2\.4\.21[0-9]+$ ]] && up_to_3.0.0
|
||||||
|
[[ "$INSTALLEDVERSION" =~ ^3\.0\.[0-9]+$ ]] && up_to_3.1.0
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,6 +372,7 @@ postupgrade_changes() {
|
|||||||
echo "Running post upgrade processes."
|
echo "Running post upgrade processes."
|
||||||
|
|
||||||
[[ "$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-9]+$ ]] && post_to_3.1.0
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,6 +471,27 @@ post_to_3.0.0() {
|
|||||||
|
|
||||||
### 3.0.0 End ###
|
### 3.0.0 End ###
|
||||||
|
|
||||||
|
### 3.1.0 Start ###
|
||||||
|
|
||||||
|
up_to_3.1.0() {
|
||||||
|
INSTALLEDVERSION=3.1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
post_to_3.1.0() {
|
||||||
|
# Provision per-minion Telegraf Postgres users for every minion known to the
|
||||||
|
# manager. postgres.auth iterates manage.up to generate any missing passwords;
|
||||||
|
# postgres.telegraf_users reconciles the roles and schemas inside the so-postgres
|
||||||
|
# container. Then push a telegraf state to every minion so their telegraf.conf
|
||||||
|
# picks up the new credentials on the first apply after soup.
|
||||||
|
echo "Provisioning Telegraf Postgres users for existing minions."
|
||||||
|
salt-call --local state.apply postgres.auth postgres.telegraf_users || true
|
||||||
|
salt '*' state.sls telegraf || true
|
||||||
|
|
||||||
|
POSTVERSION=3.1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
### 3.1.0 End ###
|
||||||
|
|
||||||
repo_sync() {
|
repo_sync() {
|
||||||
echo "Sync the local repo."
|
echo "Sync the local repo."
|
||||||
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
||||||
@@ -924,7 +947,7 @@ run_network_intermediate_upgrade() {
|
|||||||
if [[ -n "$BRANCH" ]]; then
|
if [[ -n "$BRANCH" ]]; then
|
||||||
local originally_requested_so_branch="$BRANCH"
|
local originally_requested_so_branch="$BRANCH"
|
||||||
else
|
else
|
||||||
local originally_requested_so_branch="3/main"
|
local originally_requested_so_branch="2.4/main"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Starting automated intermediate upgrade to $next_step_so_version."
|
echo "Starting automated intermediate upgrade to $next_step_so_version."
|
||||||
|
|||||||
26
salt/orch/telegraf_postgres_sync.sls
Normal file
26
salt/orch/telegraf_postgres_sync.sls
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
{% set MINION = salt['pillar.get']('minion_id') %}
|
||||||
|
{% set MANAGER = salt['pillar.get']('setup:manager') or salt['grains.get']('master') %}
|
||||||
|
|
||||||
|
manager_sync_telegraf_pg_users:
|
||||||
|
salt.state:
|
||||||
|
- tgt: {{ MANAGER }}
|
||||||
|
- sls:
|
||||||
|
- postgres.auth
|
||||||
|
- postgres.telegraf_users
|
||||||
|
- queue: True
|
||||||
|
|
||||||
|
{% if MINION and MINION != MANAGER %}
|
||||||
|
{{ MINION }}_apply_telegraf:
|
||||||
|
salt.state:
|
||||||
|
- tgt: {{ MINION }}
|
||||||
|
- sls:
|
||||||
|
- telegraf
|
||||||
|
- queue: True
|
||||||
|
- require:
|
||||||
|
- salt: manager_sync_telegraf_pg_users
|
||||||
|
{% endif %}
|
||||||
58
salt/postgres/auth.sls
Normal file
58
salt/postgres/auth.sls
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls in allowed_states %}
|
||||||
|
|
||||||
|
{% set DIGITS = "1234567890" %}
|
||||||
|
{% set LOWERCASE = "qwertyuiopasdfghjklzxcvbnm" %}
|
||||||
|
{% set UPPERCASE = "QWERTYUIOPASDFGHJKLZXCVBNM" %}
|
||||||
|
{% set SYMBOLS = "~!@#^&*()-_=+[]|;:,.<>?" %}
|
||||||
|
{% set CHARS = DIGITS~LOWERCASE~UPPERCASE~SYMBOLS %}
|
||||||
|
{% set so_postgres_user_pass = salt['pillar.get']('postgres:auth:users:so_postgres_user:pass', salt['random.get_str'](72, chars=CHARS)) %}
|
||||||
|
|
||||||
|
{# Per-minion Telegraf Postgres credentials. Merge currently-up minions with any #}
|
||||||
|
{# previously-known entries in pillar so existing passwords persist across runs. #}
|
||||||
|
{% set existing = salt['pillar.get']('postgres:auth:users', {}) %}
|
||||||
|
{% set up_minions = salt['saltutil.runner']('manage.up') or [] %}
|
||||||
|
{% set telegraf_users = {} %}
|
||||||
|
{% for key, entry in existing.items() %}
|
||||||
|
{%- if key.startswith('telegraf_') and entry.get('user') and entry.get('pass') %}
|
||||||
|
{%- do telegraf_users.update({key: entry}) %}
|
||||||
|
{%- endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for mid in up_minions %}
|
||||||
|
{%- set safe = mid | replace('.','_') | replace('-','_') | lower %}
|
||||||
|
{%- set key = 'telegraf_' ~ safe %}
|
||||||
|
{%- if key not in telegraf_users %}
|
||||||
|
{%- do telegraf_users.update({key: {'user': 'so_telegraf_' ~ safe, 'pass': salt['random.get_str'](72, chars=CHARS)}}) %}
|
||||||
|
{%- endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
postgres_auth_pillar:
|
||||||
|
file.managed:
|
||||||
|
- name: /opt/so/saltstack/local/pillar/postgres/auth.sls
|
||||||
|
- mode: 640
|
||||||
|
- reload_pillar: True
|
||||||
|
- contents: |
|
||||||
|
postgres:
|
||||||
|
auth:
|
||||||
|
users:
|
||||||
|
so_postgres_user:
|
||||||
|
user: so_postgres
|
||||||
|
pass: "{{ so_postgres_user_pass }}"
|
||||||
|
{% for key, entry in telegraf_users.items() %}
|
||||||
|
{{ key }}:
|
||||||
|
user: {{ entry.user }}
|
||||||
|
pass: "{{ entry.pass }}"
|
||||||
|
{% endfor %}
|
||||||
|
- show_changes: False
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
71
salt/postgres/config.sls
Normal file
71
salt/postgres/config.sls
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
{% from 'postgres/map.jinja' import PGMERGED %}
|
||||||
|
|
||||||
|
# Postgres Setup
|
||||||
|
postgresconfdir:
|
||||||
|
file.directory:
|
||||||
|
- name: /opt/so/conf/postgres
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
postgresdatadir:
|
||||||
|
file.directory:
|
||||||
|
- name: /nsm/postgres
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
postgreslogdir:
|
||||||
|
file.directory:
|
||||||
|
- name: /opt/so/log/postgres
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
postgresinitdir:
|
||||||
|
file.directory:
|
||||||
|
- name: /opt/so/conf/postgres/init
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
|
postgresinitusers:
|
||||||
|
file.managed:
|
||||||
|
- name: /opt/so/conf/postgres/init/init-users.sh
|
||||||
|
- source: salt://postgres/files/init-users.sh
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- mode: 755
|
||||||
|
|
||||||
|
postgresconf:
|
||||||
|
file.managed:
|
||||||
|
- name: /opt/so/conf/postgres/postgresql.conf
|
||||||
|
- source: salt://postgres/files/postgresql.conf.jinja
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- template: jinja
|
||||||
|
- defaults:
|
||||||
|
PGMERGED: {{ PGMERGED }}
|
||||||
|
|
||||||
|
postgres_sbin:
|
||||||
|
file.recurse:
|
||||||
|
- name: /usr/sbin
|
||||||
|
- source: salt://postgres/tools/sbin
|
||||||
|
- user: 939
|
||||||
|
- group: 939
|
||||||
|
- file_mode: 755
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
16
salt/postgres/defaults.yaml
Normal file
16
salt/postgres/defaults.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
postgres:
|
||||||
|
enabled: True
|
||||||
|
telegraf:
|
||||||
|
retention_days: 14
|
||||||
|
config:
|
||||||
|
listen_addresses: '*'
|
||||||
|
port: 5432
|
||||||
|
max_connections: 100
|
||||||
|
shared_buffers: 256MB
|
||||||
|
ssl: 'on'
|
||||||
|
ssl_cert_file: '/conf/postgres.crt'
|
||||||
|
ssl_key_file: '/conf/postgres.key'
|
||||||
|
ssl_ca_file: '/conf/ca.crt'
|
||||||
|
log_destination: 'stderr'
|
||||||
|
logging_collector: 'off'
|
||||||
|
log_min_messages: 'warning'
|
||||||
27
salt/postgres/disabled.sls
Normal file
27
salt/postgres/disabled.sls
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
|
||||||
|
include:
|
||||||
|
- postgres.sostatus
|
||||||
|
|
||||||
|
so-postgres:
|
||||||
|
docker_container.absent:
|
||||||
|
- force: True
|
||||||
|
|
||||||
|
so-postgres_so-status.disabled:
|
||||||
|
file.comment:
|
||||||
|
- name: /opt/so/conf/so-status/so-status.conf
|
||||||
|
- regex: ^so-postgres$
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
104
salt/postgres/enabled.sls
Normal file
104
salt/postgres/enabled.sls
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
|
{% from 'docker/docker.map.jinja' import DOCKERMERGED %}
|
||||||
|
{% set PASSWORD = salt['pillar.get']('secrets:postgres_pass') %}
|
||||||
|
{% set SO_POSTGRES_USER = salt['pillar.get']('postgres:auth:users:so_postgres_user:user', 'so_postgres') %}
|
||||||
|
{% set SO_POSTGRES_PASS = salt['pillar.get']('postgres:auth:users:so_postgres_user:pass', '') %}
|
||||||
|
|
||||||
|
include:
|
||||||
|
- postgres.auth
|
||||||
|
- postgres.ssl
|
||||||
|
- postgres.config
|
||||||
|
- postgres.sostatus
|
||||||
|
- postgres.telegraf_users
|
||||||
|
|
||||||
|
so-postgres:
|
||||||
|
docker_container.running:
|
||||||
|
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-postgres:{{ GLOBALS.so_version }}
|
||||||
|
- hostname: so-postgres
|
||||||
|
- networks:
|
||||||
|
- sobridge:
|
||||||
|
- ipv4_address: {{ DOCKERMERGED.containers['so-postgres'].ip }}
|
||||||
|
- port_bindings:
|
||||||
|
{% for BINDING in DOCKERMERGED.containers['so-postgres'].port_bindings %}
|
||||||
|
- {{ BINDING }}
|
||||||
|
{% endfor %}
|
||||||
|
- environment:
|
||||||
|
- POSTGRES_DB=securityonion
|
||||||
|
- POSTGRES_PASSWORD={{ PASSWORD }}
|
||||||
|
- SO_POSTGRES_USER={{ SO_POSTGRES_USER }}
|
||||||
|
- SO_POSTGRES_PASS={{ SO_POSTGRES_PASS }}
|
||||||
|
{% if DOCKERMERGED.containers['so-postgres'].extra_env %}
|
||||||
|
{% for XTRAENV in DOCKERMERGED.containers['so-postgres'].extra_env %}
|
||||||
|
- {{ XTRAENV }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
- binds:
|
||||||
|
- /opt/so/log/postgres/:/log:rw
|
||||||
|
- /nsm/postgres:/var/lib/postgresql/data:rw
|
||||||
|
- /opt/so/conf/postgres/postgresql.conf:/conf/postgresql.conf:ro
|
||||||
|
- /opt/so/conf/postgres/init/init-users.sh:/docker-entrypoint-initdb.d/init-users.sh:ro
|
||||||
|
- /etc/pki/postgres.crt:/conf/postgres.crt:ro
|
||||||
|
- /etc/pki/postgres.key:/conf/postgres.key:ro
|
||||||
|
- /etc/pki/tls/certs/intca.crt:/conf/ca.crt:ro
|
||||||
|
{% if DOCKERMERGED.containers['so-postgres'].custom_bind_mounts %}
|
||||||
|
{% for BIND in DOCKERMERGED.containers['so-postgres'].custom_bind_mounts %}
|
||||||
|
- {{ BIND }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if DOCKERMERGED.containers['so-postgres'].extra_hosts %}
|
||||||
|
- extra_hosts:
|
||||||
|
{% for XTRAHOST in DOCKERMERGED.containers['so-postgres'].extra_hosts %}
|
||||||
|
- {{ XTRAHOST }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if DOCKERMERGED.containers['so-postgres'].ulimits %}
|
||||||
|
- ulimits:
|
||||||
|
{% for ULIMIT in DOCKERMERGED.containers['so-postgres'].ulimits %}
|
||||||
|
- {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
- watch:
|
||||||
|
- file: postgresconf
|
||||||
|
- file: postgresinitusers
|
||||||
|
- x509: postgres_crt
|
||||||
|
- x509: postgres_key
|
||||||
|
- require:
|
||||||
|
- file: postgresconf
|
||||||
|
- file: postgresinitusers
|
||||||
|
- x509: postgres_crt
|
||||||
|
- x509: postgres_key
|
||||||
|
|
||||||
|
delete_so-postgres_so-status.disabled:
|
||||||
|
file.uncomment:
|
||||||
|
- name: /opt/so/conf/so-status/so-status.conf
|
||||||
|
- regex: ^so-postgres$
|
||||||
|
|
||||||
|
so_telegraf_trim:
|
||||||
|
{% if GLOBALS.telegraf_output in ['POSTGRES', 'BOTH'] %}
|
||||||
|
cron.present:
|
||||||
|
{% else %}
|
||||||
|
cron.absent:
|
||||||
|
{% endif %}
|
||||||
|
- name: /usr/sbin/so-telegraf-trim >> /opt/so/log/postgres/telegraf-trim.log 2>&1
|
||||||
|
- identifier: so_telegraf_trim
|
||||||
|
- user: root
|
||||||
|
- minute: '17'
|
||||||
|
- hour: '3'
|
||||||
|
- daymonth: '*'
|
||||||
|
- month: '*'
|
||||||
|
- dayweek: '*'
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
26
salt/postgres/files/init-users.sh
Normal file
26
salt/postgres/files/init-users.sh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Create or update application user for SOC platform access
|
||||||
|
# This script runs on first database initialization via docker-entrypoint-initdb.d
|
||||||
|
# The password is properly escaped to handle special characters
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${SO_POSTGRES_USER}') THEN
|
||||||
|
EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
||||||
|
ELSE
|
||||||
|
EXECUTE format('ALTER ROLE %I WITH PASSWORD %L', '${SO_POSTGRES_USER}', '${SO_POSTGRES_PASS}');
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE "$POSTGRES_DB" TO "$SO_POSTGRES_USER";
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
# Bootstrap the Telegraf metrics database. Per-minion roles + schemas are
|
||||||
|
# reconciled on every state.apply by postgres/telegraf_users.sls; this block
|
||||||
|
# only ensures the shared database exists on first initialization.
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
SELECT 'CREATE DATABASE so_telegraf'
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'so_telegraf')\gexec
|
||||||
|
EOSQL
|
||||||
8
salt/postgres/files/postgresql.conf.jinja
Normal file
8
salt/postgres/files/postgresql.conf.jinja
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{# 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. #}
|
||||||
|
|
||||||
|
{% for key, value in PGMERGED.config.items() %}
|
||||||
|
{{ key }} = '{{ value }}'
|
||||||
|
{% endfor %}
|
||||||
13
salt/postgres/init.sls
Normal file
13
salt/postgres/init.sls
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'postgres/map.jinja' import PGMERGED %}
|
||||||
|
|
||||||
|
include:
|
||||||
|
{% if PGMERGED.enabled %}
|
||||||
|
- postgres.enabled
|
||||||
|
{% else %}
|
||||||
|
- postgres.disabled
|
||||||
|
{% endif %}
|
||||||
7
salt/postgres/map.jinja
Normal file
7
salt/postgres/map.jinja
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
Elastic License 2.0. #}
|
||||||
|
|
||||||
|
{% import_yaml 'postgres/defaults.yaml' as PGDEFAULTS %}
|
||||||
|
{% set PGMERGED = salt['pillar.get']('postgres', PGDEFAULTS.postgres, merge=True) %}
|
||||||
7
salt/postgres/soc_postgres.yaml
Normal file
7
salt/postgres/soc_postgres.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
postgres:
|
||||||
|
telegraf:
|
||||||
|
retention_days:
|
||||||
|
description: Number of days of Telegraf metrics to keep in the so_telegraf database. Older rows are deleted nightly by so-telegraf-trim.
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
helpLink: influxdb
|
||||||
21
salt/postgres/sostatus.sls
Normal file
21
salt/postgres/sostatus.sls
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
|
||||||
|
append_so-postgres_so-status.conf:
|
||||||
|
file.append:
|
||||||
|
- name: /opt/so/conf/so-status/so-status.conf
|
||||||
|
- text: so-postgres
|
||||||
|
- unless: grep -q so-postgres /opt/so/conf/so-status/so-status.conf
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
54
salt/postgres/ssl.sls
Normal file
54
salt/postgres/ssl.sls
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
|
{% from 'ca/map.jinja' import CA %}
|
||||||
|
|
||||||
|
postgres_key:
|
||||||
|
x509.private_key_managed:
|
||||||
|
- name: /etc/pki/postgres.key
|
||||||
|
- keysize: 4096
|
||||||
|
- backup: True
|
||||||
|
- new: True
|
||||||
|
{% if salt['file.file_exists']('/etc/pki/postgres.key') -%}
|
||||||
|
- prereq:
|
||||||
|
- x509: /etc/pki/postgres.crt
|
||||||
|
{%- endif %}
|
||||||
|
- retry:
|
||||||
|
attempts: 5
|
||||||
|
interval: 30
|
||||||
|
|
||||||
|
postgres_crt:
|
||||||
|
x509.certificate_managed:
|
||||||
|
- name: /etc/pki/postgres.crt
|
||||||
|
- ca_server: {{ CA.server }}
|
||||||
|
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||||
|
- signing_policy: postgres
|
||||||
|
- private_key: /etc/pki/postgres.key
|
||||||
|
- CN: {{ GLOBALS.hostname }}
|
||||||
|
- days_remaining: 7
|
||||||
|
- days_valid: 820
|
||||||
|
- backup: True
|
||||||
|
- timeout: 30
|
||||||
|
- retry:
|
||||||
|
attempts: 5
|
||||||
|
interval: 30
|
||||||
|
|
||||||
|
postgresKeyperms:
|
||||||
|
file.managed:
|
||||||
|
- replace: False
|
||||||
|
- name: /etc/pki/postgres.key
|
||||||
|
- mode: 640
|
||||||
|
- group: 939
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
49
salt/postgres/telegraf_users.sls
Normal file
49
salt/postgres/telegraf_users.sls
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||||
|
{% if sls.split('.')[0] in allowed_states %}
|
||||||
|
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
|
|
||||||
|
{% set TG_OUT = (GLOBALS.telegraf_output | default('INFLUXDB')) | upper %}
|
||||||
|
{% if TG_OUT in ['POSTGRES', 'BOTH'] %}
|
||||||
|
|
||||||
|
{% set users = salt['pillar.get']('postgres:auth:users', {}) %}
|
||||||
|
{% for key, entry in users.items() %}
|
||||||
|
{% if key.startswith('telegraf_') and entry.get('user') and entry.get('pass') %}
|
||||||
|
{% set u = entry.user %}
|
||||||
|
{% set p = entry.pass | replace("'", "''") %}
|
||||||
|
|
||||||
|
postgres_telegraf_role_{{ u }}:
|
||||||
|
cmd.run:
|
||||||
|
- name: |
|
||||||
|
docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d so_telegraf <<'EOSQL'
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '{{ u }}') THEN
|
||||||
|
EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', '{{ u }}', '{{ p }}');
|
||||||
|
ELSE
|
||||||
|
EXECUTE format('ALTER ROLE %I WITH PASSWORD %L', '{{ u }}', '{{ p }}');
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
GRANT CONNECT ON DATABASE so_telegraf TO "{{ u }}";
|
||||||
|
CREATE SCHEMA IF NOT EXISTS "{{ u }}" AUTHORIZATION "{{ u }}";
|
||||||
|
EOSQL
|
||||||
|
- require:
|
||||||
|
- docker_container: so-postgres
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{{sls}}_state_not_allowed:
|
||||||
|
test.fail_without_changes:
|
||||||
|
- name: {{sls}}_state_not_allowed
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
80
salt/postgres/tools/sbin/so-postgres-manage
Normal file
80
salt/postgres/tools/sbin/so-postgres-manage
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <operation> [args]"
|
||||||
|
echo ""
|
||||||
|
echo "Supported Operations:"
|
||||||
|
echo " sql Execute a SQL command, requires: <sql>"
|
||||||
|
echo " sqlfile Execute a SQL file, requires: <path>"
|
||||||
|
echo " shell Open an interactive psql shell"
|
||||||
|
echo " dblist List databases"
|
||||||
|
echo " userlist List database roles"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for prerequisites
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This script must be run using sudo!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMMAND=$(basename $0)
|
||||||
|
OP=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo -e "$(date) | $COMMAND | $@" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
so_psql() {
|
||||||
|
docker exec so-postgres psql -U postgres -d securityonion "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$OP" in
|
||||||
|
|
||||||
|
sql)
|
||||||
|
[ $# -lt 1 ] && usage
|
||||||
|
so_psql -c "$1"
|
||||||
|
;;
|
||||||
|
|
||||||
|
sqlfile)
|
||||||
|
[ $# -ne 1 ] && usage
|
||||||
|
if [ ! -f "$1" ]; then
|
||||||
|
log "File not found: $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
docker cp "$1" so-postgres:/tmp/sqlfile.sql
|
||||||
|
docker exec so-postgres psql -U postgres -d securityonion -f /tmp/sqlfile.sql
|
||||||
|
docker exec so-postgres rm -f /tmp/sqlfile.sql
|
||||||
|
;;
|
||||||
|
|
||||||
|
shell)
|
||||||
|
docker exec -it so-postgres psql -U postgres -d securityonion
|
||||||
|
;;
|
||||||
|
|
||||||
|
dblist)
|
||||||
|
so_psql -c "\l"
|
||||||
|
;;
|
||||||
|
|
||||||
|
userlist)
|
||||||
|
so_psql -c "\du"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
10
salt/postgres/tools/sbin/so-postgres-restart
Normal file
10
salt/postgres/tools/sbin/so-postgres-restart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
/usr/sbin/so-restart postgres $1
|
||||||
10
salt/postgres/tools/sbin/so-postgres-start
Normal file
10
salt/postgres/tools/sbin/so-postgres-start
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
/usr/sbin/so-start postgres $1
|
||||||
10
salt/postgres/tools/sbin/so-postgres-stop
Normal file
10
salt/postgres/tools/sbin/so-postgres-stop
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
# Elastic License 2.0.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
/usr/sbin/so-stop postgres $1
|
||||||
110
salt/postgres/tools/sbin/so-show-stats
Normal file
110
salt/postgres/tools/sbin/so-show-stats
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
# Point-in-time host metrics from the Telegraf Postgres backend.
|
||||||
|
# Sanity-check tool for verifying metrics are landing before the grid
|
||||||
|
# dashboards consume them.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $0 [minion_id]
|
||||||
|
|
||||||
|
Shows the most recent CPU, memory, disk, and load metrics for each minion
|
||||||
|
from the so_telegraf Postgres database. Without an argument, reports on
|
||||||
|
every minion that has data. With a minion_id, limits output to that one.
|
||||||
|
|
||||||
|
Requires: sudo, so-postgres running, global.telegraf_output set to
|
||||||
|
POSTGRES or BOTH.
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This script must be run using sudo!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help) usage ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
FILTER_MINION="${1:-}"
|
||||||
|
|
||||||
|
so_psql() {
|
||||||
|
docker exec so-postgres psql -U postgres -d so_telegraf -At -F $'\t' "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! docker exec so-postgres psql -U postgres -lqt 2>/dev/null | cut -d\| -f1 | grep -qw so_telegraf; then
|
||||||
|
echo "Database so_telegraf not found. Is global.telegraf_output set to POSTGRES or BOTH?"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# List telegraf schemas (role-per-minion naming convention: so_telegraf_<sanitized_minion_id>)
|
||||||
|
SCHEMAS=$(so_psql -c "SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'so_telegraf_%' ORDER BY schema_name;")
|
||||||
|
|
||||||
|
if [ -z "$SCHEMAS" ]; then
|
||||||
|
echo "No minion schemas found in so_telegraf."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_metric() {
|
||||||
|
local schema="$1" table="$2" query="$3"
|
||||||
|
# Confirm table exists in this schema before querying
|
||||||
|
local exists
|
||||||
|
exists=$(so_psql -c "SELECT 1 FROM information_schema.tables WHERE table_schema='${schema}' AND table_name='${table}' LIMIT 1;")
|
||||||
|
[ -z "$exists" ] && return 0
|
||||||
|
so_psql -c "$query"
|
||||||
|
}
|
||||||
|
|
||||||
|
for schema in $SCHEMAS; do
|
||||||
|
minion="${schema#so_telegraf_}"
|
||||||
|
if [ -n "$FILTER_MINION" ]; then
|
||||||
|
# Compare against the sanitized form used in schema names
|
||||||
|
want=$(echo "$FILTER_MINION" | tr '.-' '_' | tr '[:upper:]' '[:lower:]')
|
||||||
|
[ "$minion" != "$want" ] && continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===================================================================="
|
||||||
|
echo " Minion: $minion"
|
||||||
|
echo "===================================================================="
|
||||||
|
|
||||||
|
print_metric "$schema" "cpu" "
|
||||||
|
SELECT 'cpu ' AS metric,
|
||||||
|
to_char(time, 'YYYY-MM-DD HH24:MI:SS') AS ts,
|
||||||
|
round((100 - usage_idle)::numeric, 1) || '% used'
|
||||||
|
FROM \"${schema}\".cpu
|
||||||
|
WHERE cpu = 'cpu-total'
|
||||||
|
ORDER BY time DESC LIMIT 1;"
|
||||||
|
|
||||||
|
print_metric "$schema" "mem" "
|
||||||
|
SELECT 'memory ' AS metric,
|
||||||
|
to_char(time, 'YYYY-MM-DD HH24:MI:SS') AS ts,
|
||||||
|
round(used_percent::numeric, 1) || '% used (' ||
|
||||||
|
pg_size_pretty(used) || ' of ' || pg_size_pretty(total) || ')'
|
||||||
|
FROM \"${schema}\".mem
|
||||||
|
ORDER BY time DESC LIMIT 1;"
|
||||||
|
|
||||||
|
print_metric "$schema" "disk" "
|
||||||
|
SELECT 'disk ' || rpad(path, 8) AS metric,
|
||||||
|
to_char(time, 'YYYY-MM-DD HH24:MI:SS') AS ts,
|
||||||
|
round(used_percent::numeric, 1) || '% used (' ||
|
||||||
|
pg_size_pretty(used) || ' of ' || pg_size_pretty(total) || ')'
|
||||||
|
FROM \"${schema}\".disk
|
||||||
|
WHERE time = (SELECT max(time) FROM \"${schema}\".disk)
|
||||||
|
ORDER BY path;"
|
||||||
|
|
||||||
|
print_metric "$schema" "system" "
|
||||||
|
SELECT 'load ' AS metric,
|
||||||
|
to_char(time, 'YYYY-MM-DD HH24:MI:SS') AS ts,
|
||||||
|
load1 || ' / ' || load5 || ' / ' || load15 || ' (1/5/15m)'
|
||||||
|
FROM \"${schema}\".system
|
||||||
|
ORDER BY time DESC LIMIT 1;"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
103
salt/postgres/tools/sbin/so-telegraf-trim
Normal file
103
salt/postgres/tools/sbin/so-telegraf-trim
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
# Deletes Telegraf metric rows older than the configured retention window from
|
||||||
|
# every minion schema in the so_telegraf database. Intended to run daily from
|
||||||
|
# cron. Retention comes from pillar (postgres.telegraf.retention_days),
|
||||||
|
# defaulting to 14 days. An explicit --days argument overrides the pillar.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $0 [--days N] [--dry-run]
|
||||||
|
|
||||||
|
--days N Override retention in days (default: pillar
|
||||||
|
postgres.telegraf.retention_days, fallback 14)
|
||||||
|
--dry-run Report what would be deleted without modifying anything
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This script must be run using sudo!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DAYS=""
|
||||||
|
DRY_RUN=0
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--days) DAYS="$2"; shift 2 ;;
|
||||||
|
--dry-run) DRY_RUN=1; shift ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$DAYS" ]; then
|
||||||
|
DAYS=$(salt-call --local --out=newline_values_only pillar.get postgres:telegraf:retention_days 2>/dev/null)
|
||||||
|
fi
|
||||||
|
if ! [[ "$DAYS" =~ ^[0-9]+$ ]] || [ "$DAYS" -lt 1 ]; then
|
||||||
|
DAYS=14
|
||||||
|
fi
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "$(date '+%Y-%m-%d %H:%M:%S') so-telegraf-trim: $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
so_psql() {
|
||||||
|
docker exec so-postgres psql -U postgres -d so_telegraf -At -F $'\t' "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! docker exec so-postgres psql -U postgres -lqt 2>/dev/null | cut -d\| -f1 | grep -qw so_telegraf; then
|
||||||
|
log "Database so_telegraf not present; nothing to trim."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Trimming rows older than ${DAYS} days (dry_run=${DRY_RUN})."
|
||||||
|
|
||||||
|
TOTAL_DELETED=0
|
||||||
|
|
||||||
|
# One row per (schema, table) we might want to trim.
|
||||||
|
# Column name is 'time' for all telegraf output plugin tables; skip metadata
|
||||||
|
# tables (tag_* used for tags_as_foreign_keys).
|
||||||
|
ROWS=$(so_psql -c "
|
||||||
|
SELECT table_schema || '.' || table_name
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE column_name = 'time'
|
||||||
|
AND data_type IN ('timestamp with time zone', 'timestamp without time zone')
|
||||||
|
AND table_schema LIKE 'so_telegraf_%'
|
||||||
|
ORDER BY 1;")
|
||||||
|
|
||||||
|
if [ -z "$ROWS" ]; then
|
||||||
|
log "No telegraf metric tables found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for qualified in $ROWS; do
|
||||||
|
if [ "$DRY_RUN" -eq 1 ]; then
|
||||||
|
count=$(so_psql -c "SELECT count(*) FROM \"${qualified%.*}\".\"${qualified#*.}\" WHERE time < now() - interval '${DAYS} days';")
|
||||||
|
log "would delete ${count:-0} rows from ${qualified}"
|
||||||
|
else
|
||||||
|
# RETURNING count via a CTE so we can log how much was trimmed per table
|
||||||
|
deleted=$(so_psql -c "
|
||||||
|
WITH d AS (
|
||||||
|
DELETE FROM \"${qualified%.*}\".\"${qualified#*.}\"
|
||||||
|
WHERE time < now() - interval '${DAYS} days'
|
||||||
|
RETURNING 1
|
||||||
|
)
|
||||||
|
SELECT count(*) FROM d;")
|
||||||
|
deleted=${deleted:-0}
|
||||||
|
TOTAL_DELETED=$((TOTAL_DELETED + deleted))
|
||||||
|
[ "$deleted" -gt 0 ] && log "deleted ${deleted} rows from ${qualified}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" -eq 0 ]; then
|
||||||
|
log "Trim complete. Total rows deleted: ${TOTAL_DELETED}."
|
||||||
|
fi
|
||||||
18
salt/reactor/telegraf_user_sync.sls
Normal file
18
salt/reactor/telegraf_user_sync.sls
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
{# Fires on salt/auth. Only act on accepted keys — ignore pending/reject. #}
|
||||||
|
{% if data.get('act') == 'accept' and data.get('id') %}
|
||||||
|
|
||||||
|
{{ data['id'] }}_telegraf_pg_sync:
|
||||||
|
runner.state.orchestrate:
|
||||||
|
- args:
|
||||||
|
- mods: orch.telegraf_postgres_sync
|
||||||
|
- pillar:
|
||||||
|
minion_id: {{ data['id'] }}
|
||||||
|
|
||||||
|
{% do salt.log.info('telegraf_user_sync reactor: syncing telegraf PG user for minion %s' % data['id']) %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
@@ -62,6 +62,19 @@ engines_config:
|
|||||||
- name: /etc/salt/master.d/engines.conf
|
- name: /etc/salt/master.d/engines.conf
|
||||||
- source: salt://salt/files/engines.conf
|
- source: salt://salt/files/engines.conf
|
||||||
|
|
||||||
|
reactor_config_telegraf:
|
||||||
|
file.managed:
|
||||||
|
- name: /etc/salt/master.d/reactor_telegraf.conf
|
||||||
|
- contents: |
|
||||||
|
reactor:
|
||||||
|
- 'salt/auth':
|
||||||
|
- /opt/so/saltstack/default/salt/reactor/telegraf_user_sync.sls
|
||||||
|
- user: root
|
||||||
|
- group: root
|
||||||
|
- mode: 644
|
||||||
|
- watch_in:
|
||||||
|
- service: salt_master_service
|
||||||
|
|
||||||
# update the bootstrap script when used for salt-cloud
|
# update the bootstrap script when used for salt-cloud
|
||||||
salt_bootstrap_cloud:
|
salt_bootstrap_cloud:
|
||||||
file.managed:
|
file.managed:
|
||||||
|
|||||||
@@ -24,6 +24,11 @@
|
|||||||
|
|
||||||
{% do SOCDEFAULTS.soc.config.server.modules.elastic.update({'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'password': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}) %}
|
{% do SOCDEFAULTS.soc.config.server.modules.elastic.update({'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'password': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}) %}
|
||||||
|
|
||||||
|
{% if GLOBALS.postgres is defined and GLOBALS.postgres.auth is defined %}
|
||||||
|
{% set PG_ADMIN_PASS = salt['pillar.get']('secrets:postgres_pass', '') %}
|
||||||
|
{% do SOCDEFAULTS.soc.config.server.modules.update({'postgres': {'hostUrl': GLOBALS.manager_ip, 'port': 5432, 'username': GLOBALS.postgres.auth.users.so_postgres_user.user, 'password': GLOBALS.postgres.auth.users.so_postgres_user.pass, 'adminUser': 'postgres', 'adminPassword': PG_ADMIN_PASS, 'dbname': 'securityonion', 'sslMode': 'require', 'assistantEnabled': true, 'esHostUrl': 'https://' ~ GLOBALS.manager_ip ~ ':9200', 'esUsername': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'esPassword': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}}) %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'hostUrl': 'https://' ~ GLOBALS.influxdb_host ~ ':8086'}) %}
|
{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'hostUrl': 'https://' ~ GLOBALS.influxdb_host ~ ':8086'}) %}
|
||||||
{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'token': INFLUXDB_TOKEN}) %}
|
{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'token': INFLUXDB_TOKEN}) %}
|
||||||
{% for tool in SOCDEFAULTS.soc.config.server.client.tools %}
|
{% for tool in SOCDEFAULTS.soc.config.server.client.tools %}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
{%- set ZEEK_ENABLED = salt['pillar.get']('zeek:enabled', True) %}
|
{%- set ZEEK_ENABLED = salt['pillar.get']('zeek:enabled', True) %}
|
||||||
{%- set MDENGINE = GLOBALS.md_engine %}
|
{%- set MDENGINE = GLOBALS.md_engine %}
|
||||||
{%- set LOGSTASH_ENABLED = LOGSTASH_MERGED.enabled %}
|
{%- set LOGSTASH_ENABLED = LOGSTASH_MERGED.enabled %}
|
||||||
|
{%- set TG_OUT = GLOBALS.telegraf_output | upper %}
|
||||||
|
{%- set PG_HOST = GLOBALS.manager_ip %}
|
||||||
|
{%- set PG_SAFE = GLOBALS.minion_id | replace('.','_') | replace('-','_') | lower %}
|
||||||
|
{%- set PG_USER = 'so_telegraf_' ~ PG_SAFE %}
|
||||||
|
{%- set PG_PASS = salt['pillar.get']('postgres:auth:users:telegraf_' ~ PG_SAFE ~ ':pass', '') %}
|
||||||
# Global tags can be specified here in key="value" format.
|
# Global tags can be specified here in key="value" format.
|
||||||
[global_tags]
|
[global_tags]
|
||||||
role = "{{ GLOBALS.role.split('-') | last }}"
|
role = "{{ GLOBALS.role.split('-') | last }}"
|
||||||
@@ -72,6 +77,7 @@
|
|||||||
# OUTPUT PLUGINS #
|
# OUTPUT PLUGINS #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
{%- if TG_OUT in ['INFLUXDB', 'BOTH'] %}
|
||||||
# Configuration for sending metrics to InfluxDB
|
# Configuration for sending metrics to InfluxDB
|
||||||
[[outputs.influxdb_v2]]
|
[[outputs.influxdb_v2]]
|
||||||
urls = ["https://{{ INFLUXDBHOST }}:8086"]
|
urls = ["https://{{ INFLUXDBHOST }}:8086"]
|
||||||
@@ -85,6 +91,15 @@
|
|||||||
tls_key = "/etc/telegraf/telegraf.key"
|
tls_key = "/etc/telegraf/telegraf.key"
|
||||||
## Use TLS but skip chain & host verification
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = false
|
# insecure_skip_verify = false
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
{%- if TG_OUT in ['POSTGRES', 'BOTH'] %}
|
||||||
|
# Configuration for sending metrics to PostgreSQL
|
||||||
|
[[outputs.postgresql]]
|
||||||
|
connection = "host={{ PG_HOST }} port=5432 user={{ PG_USER }} password={{ PG_PASS }} dbname=so_telegraf sslmode=verify-full sslrootcert=/etc/telegraf/ca.crt"
|
||||||
|
schema = "{{ PG_USER }}"
|
||||||
|
tags_as_foreign_keys = true
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# PROCESSOR PLUGINS #
|
# PROCESSOR PLUGINS #
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ base:
|
|||||||
- backup.config_backup
|
- backup.config_backup
|
||||||
- nginx
|
- nginx
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- soc
|
- soc
|
||||||
- kratos
|
- kratos
|
||||||
- hydra
|
- hydra
|
||||||
@@ -95,6 +96,7 @@ base:
|
|||||||
- backup.config_backup
|
- backup.config_backup
|
||||||
- nginx
|
- nginx
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- soc
|
- soc
|
||||||
- kratos
|
- kratos
|
||||||
- hydra
|
- hydra
|
||||||
@@ -123,6 +125,7 @@ base:
|
|||||||
- registry
|
- registry
|
||||||
- nginx
|
- nginx
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- strelka.manager
|
- strelka.manager
|
||||||
- soc
|
- soc
|
||||||
- kratos
|
- kratos
|
||||||
@@ -153,6 +156,7 @@ base:
|
|||||||
- registry
|
- registry
|
||||||
- nginx
|
- nginx
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- strelka.manager
|
- strelka.manager
|
||||||
- soc
|
- soc
|
||||||
- kratos
|
- kratos
|
||||||
@@ -181,6 +185,7 @@ base:
|
|||||||
- manager
|
- manager
|
||||||
- nginx
|
- nginx
|
||||||
- influxdb
|
- influxdb
|
||||||
|
- postgres
|
||||||
- strelka.manager
|
- strelka.manager
|
||||||
- soc
|
- soc
|
||||||
- kratos
|
- kratos
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
||||||
|
{% from 'vars/postgres.map.jinja' import POSTGRES_GLOBALS %}
|
||||||
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
||||||
|
|
||||||
{% set ROLE_GLOBALS = {} %}
|
{% set ROLE_GLOBALS = {} %}
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
{% set EVAL_GLOBALS =
|
{% set EVAL_GLOBALS =
|
||||||
[
|
[
|
||||||
ELASTICSEARCH_GLOBALS,
|
ELASTICSEARCH_GLOBALS,
|
||||||
|
POSTGRES_GLOBALS,
|
||||||
SENSOR_GLOBALS
|
SENSOR_GLOBALS
|
||||||
]
|
]
|
||||||
%}
|
%}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
'md_engine': INIT.PILLAR.global.mdengine,
|
'md_engine': INIT.PILLAR.global.mdengine,
|
||||||
'pcap_engine': GLOBALMERGED.pcapengine,
|
'pcap_engine': GLOBALMERGED.pcapengine,
|
||||||
'pipeline': GLOBALMERGED.pipeline,
|
'pipeline': GLOBALMERGED.pipeline,
|
||||||
|
'telegraf_output': GLOBALMERGED.telegraf_output,
|
||||||
'so_version': INIT.PILLAR.global.soversion,
|
'so_version': INIT.PILLAR.global.soversion,
|
||||||
'so_docker_gateway': DOCKERMERGED.gateway,
|
'so_docker_gateway': DOCKERMERGED.gateway,
|
||||||
'so_docker_range': DOCKERMERGED.range,
|
'so_docker_range': DOCKERMERGED.range,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
||||||
|
{% from 'vars/postgres.map.jinja' import POSTGRES_GLOBALS %}
|
||||||
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
||||||
|
|
||||||
{% set ROLE_GLOBALS = {} %}
|
{% set ROLE_GLOBALS = {} %}
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
{% set IMPORT_GLOBALS =
|
{% set IMPORT_GLOBALS =
|
||||||
[
|
[
|
||||||
ELASTICSEARCH_GLOBALS,
|
ELASTICSEARCH_GLOBALS,
|
||||||
|
POSTGRES_GLOBALS,
|
||||||
SENSOR_GLOBALS
|
SENSOR_GLOBALS
|
||||||
]
|
]
|
||||||
%}
|
%}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
||||||
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
||||||
|
{% from 'vars/postgres.map.jinja' import POSTGRES_GLOBALS %}
|
||||||
|
|
||||||
{% set ROLE_GLOBALS = {} %}
|
{% set ROLE_GLOBALS = {} %}
|
||||||
|
|
||||||
{% set MANAGER_GLOBALS =
|
{% set MANAGER_GLOBALS =
|
||||||
[
|
[
|
||||||
ELASTICSEARCH_GLOBALS,
|
ELASTICSEARCH_GLOBALS,
|
||||||
LOGSTASH_GLOBALS
|
LOGSTASH_GLOBALS,
|
||||||
|
POSTGRES_GLOBALS
|
||||||
]
|
]
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
||||||
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
||||||
|
{% from 'vars/postgres.map.jinja' import POSTGRES_GLOBALS %}
|
||||||
|
|
||||||
{% set ROLE_GLOBALS = {} %}
|
{% set ROLE_GLOBALS = {} %}
|
||||||
|
|
||||||
{% set MANAGERSEARCH_GLOBALS =
|
{% set MANAGERSEARCH_GLOBALS =
|
||||||
[
|
[
|
||||||
ELASTICSEARCH_GLOBALS,
|
ELASTICSEARCH_GLOBALS,
|
||||||
LOGSTASH_GLOBALS
|
LOGSTASH_GLOBALS,
|
||||||
|
POSTGRES_GLOBALS
|
||||||
]
|
]
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|||||||
16
salt/vars/postgres.map.jinja
Normal file
16
salt/vars/postgres.map.jinja
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||||
|
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||||
|
https://securityonion.net/license; you may not use this file except in compliance with the
|
||||||
|
Elastic License 2.0. #}
|
||||||
|
|
||||||
|
{% import 'vars/init.map.jinja' as INIT %}
|
||||||
|
|
||||||
|
{%
|
||||||
|
set POSTGRES_GLOBALS = {
|
||||||
|
'postgres': {}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/postgres/auth.sls') %}
|
||||||
|
{% do POSTGRES_GLOBALS.postgres.update({'auth': INIT.PILLAR.postgres.auth}) %}
|
||||||
|
{% endif %}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
{% from 'vars/elasticsearch.map.jinja' import ELASTICSEARCH_GLOBALS %}
|
||||||
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
{% from 'vars/logstash.map.jinja' import LOGSTASH_GLOBALS %}
|
||||||
|
{% from 'vars/postgres.map.jinja' import POSTGRES_GLOBALS %}
|
||||||
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
{% from 'vars/sensor.map.jinja' import SENSOR_GLOBALS %}
|
||||||
|
|
||||||
{% set ROLE_GLOBALS = {} %}
|
{% set ROLE_GLOBALS = {} %}
|
||||||
@@ -8,6 +9,7 @@
|
|||||||
[
|
[
|
||||||
ELASTICSEARCH_GLOBALS,
|
ELASTICSEARCH_GLOBALS,
|
||||||
LOGSTASH_GLOBALS,
|
LOGSTASH_GLOBALS,
|
||||||
|
POSTGRES_GLOBALS,
|
||||||
SENSOR_GLOBALS
|
SENSOR_GLOBALS
|
||||||
]
|
]
|
||||||
%}
|
%}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ zeek:
|
|||||||
helpLink: zeek
|
helpLink: zeek
|
||||||
ja4plus:
|
ja4plus:
|
||||||
enabled:
|
enabled:
|
||||||
description: "Enables JA4+ fingerprinting (JA4S, JA4D, JA4H, JA4L, JA4SSH, JA4T, JA4TS, JA4X). By enabling this, you agree to the terms of the JA4+ license [https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE-JA4](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE-JA4)."
|
description: "Enables JA4+ fingerprinting (JA4S, JA4D, JA4H, JA4L, JA4SSH, JA4T, JA4TS, JA4X). By enabling this, you agree to the terms of the JA4+ license [https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE)."
|
||||||
forcedType: bool
|
forcedType: bool
|
||||||
helpLink: zeek
|
helpLink: zeek
|
||||||
advanced: False
|
advanced: False
|
||||||
|
|||||||
@@ -821,6 +821,7 @@ create_manager_pillars() {
|
|||||||
soc_pillar
|
soc_pillar
|
||||||
idh_pillar
|
idh_pillar
|
||||||
influxdb_pillar
|
influxdb_pillar
|
||||||
|
postgres_pillar
|
||||||
logrotate_pillar
|
logrotate_pillar
|
||||||
patch_pillar
|
patch_pillar
|
||||||
nginx_pillar
|
nginx_pillar
|
||||||
@@ -1053,6 +1054,7 @@ generate_passwords(){
|
|||||||
HYDRAKEY=$(get_random_value)
|
HYDRAKEY=$(get_random_value)
|
||||||
HYDRASALT=$(get_random_value)
|
HYDRASALT=$(get_random_value)
|
||||||
REDISPASS=$(get_random_value)
|
REDISPASS=$(get_random_value)
|
||||||
|
POSTGRESPASS=$(get_random_value)
|
||||||
SOCSRVKEY=$(get_random_value 64)
|
SOCSRVKEY=$(get_random_value 64)
|
||||||
IMPORTPASS=$(get_random_value)
|
IMPORTPASS=$(get_random_value)
|
||||||
}
|
}
|
||||||
@@ -1355,6 +1357,12 @@ influxdb_pillar() {
|
|||||||
" token: $INFLUXTOKEN" > $local_salt_dir/pillar/influxdb/token.sls
|
" token: $INFLUXTOKEN" > $local_salt_dir/pillar/influxdb/token.sls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postgres_pillar() {
|
||||||
|
title "Create the postgres pillar file"
|
||||||
|
touch $adv_postgres_pillar_file
|
||||||
|
touch $postgres_pillar_file
|
||||||
|
}
|
||||||
|
|
||||||
make_some_dirs() {
|
make_some_dirs() {
|
||||||
mkdir -p /nsm
|
mkdir -p /nsm
|
||||||
mkdir -p "$default_salt_dir"
|
mkdir -p "$default_salt_dir"
|
||||||
@@ -1364,7 +1372,7 @@ make_some_dirs() {
|
|||||||
mkdir -p $local_salt_dir/salt/firewall/portgroups
|
mkdir -p $local_salt_dir/salt/firewall/portgroups
|
||||||
mkdir -p $local_salt_dir/salt/firewall/ports
|
mkdir -p $local_salt_dir/salt/firewall/ports
|
||||||
|
|
||||||
for THEDIR in bpf elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idh elastalert stig global kafka versionlock hypervisor vm; do
|
for THEDIR in bpf elasticsearch ntp firewall redis backup influxdb postgres strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idh elastalert stig global kafka versionlock hypervisor vm; do
|
||||||
mkdir -p $local_salt_dir/pillar/$THEDIR
|
mkdir -p $local_salt_dir/pillar/$THEDIR
|
||||||
touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls
|
touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls
|
||||||
touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls
|
touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls
|
||||||
@@ -1832,7 +1840,8 @@ secrets_pillar(){
|
|||||||
printf '%s\n'\
|
printf '%s\n'\
|
||||||
"secrets:"\
|
"secrets:"\
|
||||||
" import_pass: $IMPORTPASS"\
|
" import_pass: $IMPORTPASS"\
|
||||||
" influx_pass: $INFLUXPASS" > $local_salt_dir/pillar/secrets.sls
|
" influx_pass: $INFLUXPASS"\
|
||||||
|
" postgres_pass: $POSTGRESPASS" > $local_salt_dir/pillar/secrets.sls
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,12 @@ export influxdb_pillar_file
|
|||||||
adv_influxdb_pillar_file="$local_salt_dir/pillar/influxdb/adv_influxdb.sls"
|
adv_influxdb_pillar_file="$local_salt_dir/pillar/influxdb/adv_influxdb.sls"
|
||||||
export adv_influxdb_pillar_file
|
export adv_influxdb_pillar_file
|
||||||
|
|
||||||
|
postgres_pillar_file="$local_salt_dir/pillar/postgres/soc_postgres.sls"
|
||||||
|
export postgres_pillar_file
|
||||||
|
|
||||||
|
adv_postgres_pillar_file="$local_salt_dir/pillar/postgres/adv_postgres.sls"
|
||||||
|
export adv_postgres_pillar_file
|
||||||
|
|
||||||
logrotate_pillar_file="$local_salt_dir/pillar/logrotate/soc_logrotate.sls"
|
logrotate_pillar_file="$local_salt_dir/pillar/logrotate/soc_logrotate.sls"
|
||||||
export logrotate_pillar_file
|
export logrotate_pillar_file
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user