mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-02-20 06:05:01 +01:00
Compare commits
239 Commits
c4a70b540e
...
mwright/ge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90eee49ab6 | ||
|
|
f025886b31 | ||
|
|
7fa01f5fd5 | ||
|
|
93f52453b4 | ||
|
|
a9307aa308 | ||
|
|
8fc3011f92 | ||
|
|
911c9d56db | ||
|
|
c1273c3d2c | ||
|
|
d0018c9333 | ||
|
|
3349c1a936 | ||
|
|
32819c8635 | ||
|
|
58c0a9183c | ||
|
|
7dfd212519 | ||
|
|
b8fb0fa735 | ||
|
|
e6f767b613 | ||
|
|
d00fb4ccf7 | ||
|
|
a29eff37a0 | ||
|
|
534a0ad41f | ||
|
|
4c86275cd6 | ||
|
|
a1c806a944 | ||
|
|
3d1a2c12ec | ||
|
|
8538e5572e | ||
|
|
9b525612a8 | ||
|
|
fb364aec5d | ||
|
|
ed014b431e | ||
|
|
82ca64d66f | ||
|
|
7e0fb73fec | ||
|
|
c28bcfa85e | ||
|
|
be6d94d65b | ||
|
|
ada463320b | ||
|
|
2b05583035 | ||
|
|
4d6b2de374 | ||
|
|
41d94b6bfd | ||
|
|
2d74002e9e | ||
|
|
04a757dde0 | ||
|
|
e7e379ce82 | ||
|
|
fe0178b8ac | ||
|
|
0661c3af1a | ||
|
|
4778bd6680 | ||
|
|
5033462098 | ||
|
|
6b4b1d74fd | ||
|
|
f0df6a171c | ||
|
|
dc4cd93c02 | ||
|
|
19157aa76c | ||
|
|
1c092bf791 | ||
|
|
ff8790b35b | ||
|
|
c6168c1487 | ||
|
|
c431ac3765 | ||
|
|
6ff4901067 | ||
|
|
eea14b493c | ||
|
|
6b98c5a10d | ||
|
|
6d5ac5a16b | ||
|
|
42060a9112 | ||
|
|
cca4bec43f | ||
|
|
9e7c304ea1 | ||
|
|
d540b024b2 | ||
|
|
cf1c3ac38d | ||
|
|
a99c553ada | ||
|
|
b1575237fc | ||
|
|
6ce6eb95d6 | ||
|
|
b3d1dd51a4 | ||
|
|
fd29fdd975 | ||
|
|
2de98b1397 | ||
|
|
1d57c02608 | ||
|
|
ebeeb91297 | ||
|
|
6282beb6bd | ||
|
|
1c06bddb09 | ||
|
|
36f8c490c8 | ||
|
|
94c1a641d8 | ||
|
|
057131dce7 | ||
|
|
e5226b50ed | ||
|
|
ff4ec69f7c | ||
|
|
4ad6136d98 | ||
|
|
006c17bdca | ||
|
|
6b1939b827 | ||
|
|
2038227308 | ||
|
|
950852d673 | ||
|
|
8900f9ade3 | ||
|
|
8cf0d59560 | ||
|
|
a78e0b0871 | ||
|
|
32f030f6f6 | ||
|
|
b0d87b49c6 | ||
|
|
55b3fa389e | ||
|
|
b3ae716929 | ||
|
|
5d0c187497 | ||
|
|
30d8cf5a6c | ||
|
|
07dbdb9f8f | ||
|
|
b4c8f7924a | ||
|
|
809422c517 | ||
|
|
bb7593a53a | ||
|
|
8e3ba8900f | ||
|
|
005ec87248 | ||
|
|
4c6ff0641b | ||
|
|
3e242913e9 | ||
|
|
ba68e3c9bd | ||
|
|
e1199a91b9 | ||
|
|
d381248e30 | ||
|
|
f4f0218cae | ||
|
|
7a38e52b01 | ||
|
|
959fd55e32 | ||
|
|
a8e218a9ff | ||
|
|
3f5cd46d7d | ||
|
|
627f0c2bcc | ||
|
|
f6bde3eb04 | ||
|
|
f6e95c17a0 | ||
|
|
1234cbd04b | ||
|
|
fd5b93542e | ||
|
|
a192455fae | ||
|
|
66f17e95aa | ||
|
|
6f4b96b61b | ||
|
|
9905d23976 | ||
|
|
17532fe49d | ||
|
|
074158b495 | ||
|
|
82d5115b3f | ||
|
|
5c63111002 | ||
|
|
6eda7932e8 | ||
|
|
399b7567dd | ||
|
|
2133ada3a1 | ||
|
|
4f6d4738c4 | ||
|
|
d430ed6727 | ||
|
|
596bc178df | ||
|
|
0cd3d7b5a8 | ||
|
|
349d77ffdf | ||
|
|
c3283b04e5 | ||
|
|
0da0788e6b | ||
|
|
6f7e249aa2 | ||
|
|
dfaeed54b6 | ||
|
|
4f59e46235 | ||
|
|
bf4cc7befb | ||
|
|
c63c6dc68b | ||
|
|
e4225d6e9b | ||
|
|
3fb153c43e | ||
|
|
6de20c63d4 | ||
|
|
00fbc1c259 | ||
|
|
3bc552ef38 | ||
|
|
ee70d94e15 | ||
|
|
1887d2c0e9 | ||
|
|
c99dd4e44f | ||
|
|
541b8b288d | ||
|
|
db168a0452 | ||
|
|
aa96cf44d4 | ||
|
|
0d59c35d2a | ||
|
|
8463bde90d | ||
|
|
150c31009e | ||
|
|
693494024d | ||
|
|
ee66d6c7d1 | ||
|
|
3effd30f7e | ||
|
|
4ab20c2454 | ||
|
|
c075b5a1a7 | ||
|
|
cb1e59fa49 | ||
|
|
588aa435ec | ||
|
|
752c764066 | ||
|
|
af604c2ea8 | ||
|
|
6c3f9f149d | ||
|
|
152f2e03f1 | ||
|
|
605797c86a | ||
|
|
1ee5b1611a | ||
|
|
5028729e4c | ||
|
|
ab00fa8809 | ||
|
|
2d705e7caa | ||
|
|
f2370043a8 | ||
|
|
3b349b9803 | ||
|
|
f2b7ffe0eb | ||
|
|
3a410eed1a | ||
|
|
a53619f10f | ||
|
|
893aaafa1b | ||
|
|
33c34cdeca | ||
|
|
9b411867df | ||
|
|
fd1596b3a0 | ||
|
|
b05de22f58 | ||
|
|
e9341ee8d3 | ||
|
|
f666ad600f | ||
|
|
9345718967 | ||
|
|
6c879cbd13 | ||
|
|
089b5aaf44 | ||
|
|
b61885add5 | ||
|
|
702ba2e0a4 | ||
|
|
5cb1e284af | ||
|
|
e3a4f0873e | ||
|
|
7977a020ac | ||
|
|
1d63269883 | ||
|
|
dd8027480b | ||
|
|
c45bd77e44 | ||
|
|
032e0abd61 | ||
|
|
8509d1e454 | ||
|
|
8ff0c6828b | ||
|
|
ddd6935e50 | ||
|
|
5588a56b24 | ||
|
|
12aed6e280 | ||
|
|
b2a469e08c | ||
|
|
285b0e4af9 | ||
|
|
f9edfd6391 | ||
|
|
c0845e1612 | ||
|
|
9878d9d37e | ||
|
|
a2196085d5 | ||
|
|
ba62a8c10c | ||
|
|
38f38e2789 | ||
|
|
1475f0fc2f | ||
|
|
a3396b77a3 | ||
|
|
8158fee8fc | ||
|
|
f6301bc3e5 | ||
|
|
6c5c176b7d | ||
|
|
c6d52b5eb1 | ||
|
|
7cac528389 | ||
|
|
d518f75468 | ||
|
|
c6fac8c36b | ||
|
|
17b5b81696 | ||
|
|
9960db200c | ||
|
|
b9ff1704b0 | ||
|
|
6fe817ca4a | ||
|
|
cb9a6fac25 | ||
|
|
a945768251 | ||
|
|
c6646e3821 | ||
|
|
99dc72cece | ||
|
|
04d6cca204 | ||
|
|
5ab6bda639 | ||
|
|
f433de7e12 | ||
|
|
8ef6c2f91d | ||
|
|
7575218697 | ||
|
|
dc945dad00 | ||
|
|
ddcd74ffd2 | ||
|
|
e105bd12e6 | ||
|
|
f5688175b6 | ||
|
|
72a4ba405f | ||
|
|
94694d394e | ||
|
|
03dd746601 | ||
|
|
eec3373ae7 | ||
|
|
db45ce07ed | ||
|
|
ba49765312 | ||
|
|
72c8c2371e | ||
|
|
80411ab6cf | ||
|
|
0ff8fa57e7 | ||
|
|
411f28a049 | ||
|
|
0f42233092 | ||
|
|
2dd49f6d9b | ||
|
|
271f545f4f | ||
|
|
545060103a | ||
|
|
36a6a59d55 | ||
|
|
33ada95bbc |
2
.github/DISCUSSION_TEMPLATE/2-4.yml
vendored
2
.github/DISCUSSION_TEMPLATE/2-4.yml
vendored
@@ -33,6 +33,8 @@ body:
|
||||
- 2.4.180
|
||||
- 2.4.190
|
||||
- 2.4.200
|
||||
- 2.4.201
|
||||
- 2.4.210
|
||||
- Other (please provide detail below)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
### 2.4.190-20251024 ISO image released on 2025/10/24
|
||||
### 2.4.201-20260114 ISO image released on 2026/1/15
|
||||
|
||||
|
||||
### Download and Verify
|
||||
|
||||
2.4.190-20251024 ISO image:
|
||||
https://download.securityonion.net/file/securityonion/securityonion-2.4.190-20251024.iso
|
||||
2.4.201-20260114 ISO image:
|
||||
https://download.securityonion.net/file/securityonion/securityonion-2.4.201-20260114.iso
|
||||
|
||||
MD5: 25358481FB876226499C011FC0710358
|
||||
SHA1: 0B26173C0CE136F2CA40A15046D1DFB78BCA1165
|
||||
SHA256: 4FD9F62EDA672408828B3C0C446FE5EA9FF3C4EE8488A7AB1101544A3C487872
|
||||
MD5: 20E926E433203798512EF46E590C89B9
|
||||
SHA1: 779E4084A3E1A209B494493B8F5658508B6014FA
|
||||
SHA256: 3D10E7C885AEC5C5D4F4E50F9644FF9728E8C0A2E36EBB8C96B32569685A7C40
|
||||
|
||||
Signature for ISO image:
|
||||
https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.190-20251024.iso.sig
|
||||
https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.201-20260114.iso.sig
|
||||
|
||||
Signing key:
|
||||
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS
|
||||
@@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.
|
||||
|
||||
Download the signature file for the ISO:
|
||||
```
|
||||
wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.190-20251024.iso.sig
|
||||
wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.201-20260114.iso.sig
|
||||
```
|
||||
|
||||
Download the ISO image:
|
||||
```
|
||||
wget https://download.securityonion.net/file/securityonion/securityonion-2.4.190-20251024.iso
|
||||
wget https://download.securityonion.net/file/securityonion/securityonion-2.4.201-20260114.iso
|
||||
```
|
||||
|
||||
Verify the downloaded ISO image using the signature file:
|
||||
```
|
||||
gpg --verify securityonion-2.4.190-20251024.iso.sig securityonion-2.4.190-20251024.iso
|
||||
gpg --verify securityonion-2.4.201-20260114.iso.sig securityonion-2.4.201-20260114.iso
|
||||
```
|
||||
|
||||
The output should show "Good signature" and the Primary key fingerprint should match what's shown below:
|
||||
```
|
||||
gpg: Signature made Thu 23 Oct 2025 07:21:46 AM EDT using RSA key ID FE507013
|
||||
gpg: Signature made Wed 14 Jan 2026 05:23:39 PM EST using RSA key ID FE507013
|
||||
gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>"
|
||||
gpg: WARNING: This key is not certified with a trusted signature!
|
||||
gpg: There is no indication that the signature belongs to the owner.
|
||||
|
||||
2
pillar/ca/init.sls
Normal file
2
pillar/ca/init.sls
Normal file
@@ -0,0 +1,2 @@
|
||||
ca:
|
||||
server:
|
||||
@@ -1,5 +1,6 @@
|
||||
base:
|
||||
'*':
|
||||
- ca
|
||||
- global.soc_global
|
||||
- global.adv_global
|
||||
- docker.soc_docker
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
'salt.minion-check',
|
||||
'sensoroni',
|
||||
'salt.lasthighstate',
|
||||
'salt.minion'
|
||||
] %}
|
||||
|
||||
{% set ssl_states = [
|
||||
'ssl',
|
||||
'salt.minion',
|
||||
'telegraf',
|
||||
'firewall',
|
||||
'schedule',
|
||||
@@ -28,7 +24,7 @@
|
||||
|
||||
{% set manager_states = [
|
||||
'salt.master',
|
||||
'ca',
|
||||
'ca.server',
|
||||
'registry',
|
||||
'manager',
|
||||
'nginx',
|
||||
@@ -75,28 +71,24 @@
|
||||
{# Map role-specific states #}
|
||||
{% set role_states = {
|
||||
'so-eval': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
sensor_states +
|
||||
elastic_stack_states | reject('equalto', 'logstash') | list
|
||||
elastic_stack_states | reject('equalto', 'logstash') | list +
|
||||
['logstash.ssl']
|
||||
),
|
||||
'so-heavynode': (
|
||||
ssl_states +
|
||||
sensor_states +
|
||||
['elasticagent', 'elasticsearch', 'logstash', 'redis', 'nginx']
|
||||
),
|
||||
'so-idh': (
|
||||
ssl_states +
|
||||
['idh']
|
||||
),
|
||||
'so-import': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
sensor_states | reject('equalto', 'strelka') | reject('equalto', 'healthcheck') | list +
|
||||
['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'strelka.manager']
|
||||
['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'logstash.ssl', 'strelka.manager']
|
||||
),
|
||||
'so-manager': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] +
|
||||
stig_states +
|
||||
@@ -104,7 +96,6 @@
|
||||
elastic_stack_states
|
||||
),
|
||||
'so-managerhype': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
['salt.cloud', 'strelka.manager', 'hypervisor', 'libvirt'] +
|
||||
stig_states +
|
||||
@@ -112,7 +103,6 @@
|
||||
elastic_stack_states
|
||||
),
|
||||
'so-managersearch': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] +
|
||||
stig_states +
|
||||
@@ -120,12 +110,10 @@
|
||||
elastic_stack_states
|
||||
),
|
||||
'so-searchnode': (
|
||||
ssl_states +
|
||||
['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash', 'nginx'] +
|
||||
stig_states
|
||||
),
|
||||
'so-standalone': (
|
||||
ssl_states +
|
||||
manager_states +
|
||||
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users'] +
|
||||
sensor_states +
|
||||
@@ -134,29 +122,24 @@
|
||||
elastic_stack_states
|
||||
),
|
||||
'so-sensor': (
|
||||
ssl_states +
|
||||
sensor_states +
|
||||
['nginx'] +
|
||||
stig_states
|
||||
),
|
||||
'so-fleet': (
|
||||
ssl_states +
|
||||
stig_states +
|
||||
['logstash', 'nginx', 'healthcheck', 'elasticfleet']
|
||||
),
|
||||
'so-receiver': (
|
||||
ssl_states +
|
||||
kafka_states +
|
||||
stig_states +
|
||||
['logstash', 'redis']
|
||||
),
|
||||
'so-hypervisor': (
|
||||
ssl_states +
|
||||
stig_states +
|
||||
['hypervisor', 'libvirt']
|
||||
),
|
||||
'so-desktop': (
|
||||
['ssl', 'docker_clean', 'telegraf'] +
|
||||
stig_states
|
||||
)
|
||||
} %}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if PCAPBPF %}
|
||||
{% set PCAP_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ PCAPBPF|join(" "), cwd='/root') %}
|
||||
{% set PCAP_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %}
|
||||
{% if PCAP_BPF_CALC['retcode'] == 0 %}
|
||||
{% set PCAP_BPF_STATUS = 1 %}
|
||||
{% set STENO_BPF_COMPILED = ",\\\"--filter=" + PCAP_BPF_CALC['stdout'] + "\\\"" %}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% set SURICATABPF = BPFMERGED.suricata %}
|
||||
|
||||
{% if SURICATABPF %}
|
||||
{% set SURICATA_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ SURICATABPF|join(" "), cwd='/root') %}
|
||||
{% set SURICATA_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %}
|
||||
{% if SURICATA_BPF_CALC['retcode'] == 0 %}
|
||||
{% set SURICATA_BPF_STATUS = 1 %}
|
||||
{% endif %}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% set ZEEKBPF = BPFMERGED.zeek %}
|
||||
|
||||
{% if ZEEKBPF %}
|
||||
{% set ZEEK_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ ZEEKBPF|join(" "), cwd='/root') %}
|
||||
{% set ZEEK_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %}
|
||||
{% if ZEEK_BPF_CALC['retcode'] == 0 %}
|
||||
{% set ZEEK_BPF_STATUS = 1 %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
pki_issued_certs:
|
||||
file.directory:
|
||||
- name: /etc/pki/issued_certs
|
||||
- makedirs: True
|
||||
@@ -3,70 +3,10 @@
|
||||
# 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 %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
|
||||
|
||||
include:
|
||||
- ca.dirs
|
||||
|
||||
/etc/salt/minion.d/signing_policies.conf:
|
||||
file.managed:
|
||||
- source: salt://ca/files/signing_policies.conf
|
||||
|
||||
pki_private_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/ca.key
|
||||
- keysize: 4096
|
||||
- passphrase:
|
||||
- backup: True
|
||||
{% if salt['file.file_exists']('/etc/pki/ca.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/ca.crt
|
||||
{%- endif %}
|
||||
|
||||
pki_public_ca_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/ca.crt
|
||||
- signing_private_key: /etc/pki/ca.key
|
||||
- CN: {{ GLOBALS.manager }}
|
||||
- C: US
|
||||
- ST: Utah
|
||||
- L: Salt Lake City
|
||||
- basicConstraints: "critical CA:true"
|
||||
- keyUsage: "critical cRLSign, keyCertSign"
|
||||
- extendedkeyUsage: "serverAuth, clientAuth"
|
||||
- subjectKeyIdentifier: hash
|
||||
- authorityKeyIdentifier: keyid:always, issuer
|
||||
- days_valid: 3650
|
||||
- days_remaining: 0
|
||||
- backup: True
|
||||
- replace: False
|
||||
- require:
|
||||
- sls: ca.dirs
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
mine_update_ca_crt:
|
||||
module.run:
|
||||
- mine.update: []
|
||||
- onchanges:
|
||||
- x509: pki_public_ca_crt
|
||||
|
||||
cakeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/ca.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% if GLOBALS.is_manager %}
|
||||
- ca.server
|
||||
{% endif %}
|
||||
- ca.trustca
|
||||
|
||||
3
salt/ca/map.jinja
Normal file
3
salt/ca/map.jinja
Normal file
@@ -0,0 +1,3 @@
|
||||
{% set CA = {
|
||||
'server': pillar.ca.server
|
||||
}%}
|
||||
@@ -1,7 +1,35 @@
|
||||
pki_private_key:
|
||||
# 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 setup_running = salt['cmd.retcode']('pgrep -x so-setup') == 0 %}
|
||||
|
||||
{% if setup_running%}
|
||||
|
||||
include:
|
||||
- ssl.remove
|
||||
|
||||
remove_pki_private_key:
|
||||
file.absent:
|
||||
- name: /etc/pki/ca.key
|
||||
|
||||
pki_public_ca_crt:
|
||||
remove_pki_public_ca_crt:
|
||||
file.absent:
|
||||
- name: /etc/pki/ca.crt
|
||||
|
||||
remove_trusttheca:
|
||||
file.absent:
|
||||
- name: /etc/pki/tls/certs/intca.crt
|
||||
|
||||
remove_pki_public_ca_crt_symlink:
|
||||
file.absent:
|
||||
- name: /opt/so/saltstack/local/salt/ca/files/ca.crt
|
||||
|
||||
{% else %}
|
||||
|
||||
so-setup_not_running:
|
||||
test.show_notification:
|
||||
- text: "This state is reserved for usage during so-setup."
|
||||
|
||||
{% endif %}
|
||||
|
||||
63
salt/ca/server.sls
Normal file
63
salt/ca/server.sls
Normal file
@@ -0,0 +1,63 @@
|
||||
# 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 %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
|
||||
pki_private_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/ca.key
|
||||
- keysize: 4096
|
||||
- passphrase:
|
||||
- backup: True
|
||||
{% if salt['file.file_exists']('/etc/pki/ca.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/ca.crt
|
||||
{%- endif %}
|
||||
|
||||
pki_public_ca_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/ca.crt
|
||||
- signing_private_key: /etc/pki/ca.key
|
||||
- CN: {{ GLOBALS.manager }}
|
||||
- C: US
|
||||
- ST: Utah
|
||||
- L: Salt Lake City
|
||||
- basicConstraints: "critical CA:true"
|
||||
- keyUsage: "critical cRLSign, keyCertSign"
|
||||
- extendedkeyUsage: "serverAuth, clientAuth"
|
||||
- subjectKeyIdentifier: hash
|
||||
- authorityKeyIdentifier: keyid:always, issuer
|
||||
- days_valid: 3650
|
||||
- days_remaining: 7
|
||||
- backup: True
|
||||
- replace: False
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
pki_public_ca_crt_symlink:
|
||||
file.symlink:
|
||||
- name: /opt/so/saltstack/local/salt/ca/files/ca.crt
|
||||
- target: /etc/pki/ca.crt
|
||||
- require:
|
||||
- x509: pki_public_ca_crt
|
||||
|
||||
cakeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/ca.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
15
salt/ca/signing_policy.sls
Normal file
15
salt/ca/signing_policy.sls
Normal file
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
# when the salt-minion signs the cert, a copy is stored here
|
||||
issued_certs_copypath:
|
||||
file.directory:
|
||||
- name: /etc/pki/issued_certs
|
||||
- makedirs: True
|
||||
|
||||
signing_policy:
|
||||
file.managed:
|
||||
- name: /etc/salt/minion.d/signing_policies.conf
|
||||
- source: salt://ca/files/signing_policies.conf
|
||||
26
salt/ca/trustca.sls
Normal file
26
salt/ca/trustca.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.
|
||||
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
|
||||
include:
|
||||
- docker
|
||||
|
||||
# Trust the CA
|
||||
trusttheca:
|
||||
file.managed:
|
||||
- name: /etc/pki/tls/certs/intca.crt
|
||||
- source: salt://ca/files/ca.crt
|
||||
- watch_in:
|
||||
- service: docker_running
|
||||
- show_changes: False
|
||||
- makedirs: True
|
||||
|
||||
{% if GLOBALS.os_family == 'Debian' %}
|
||||
symlinkca:
|
||||
file.symlink:
|
||||
- target: /etc/pki/tls/certs/intca.crt
|
||||
- name: /etc/ssl/certs/intca.crt
|
||||
{% endif %}
|
||||
@@ -177,7 +177,7 @@ so-status_script:
|
||||
- source: salt://common/tools/sbin/so-status
|
||||
- mode: 755
|
||||
|
||||
{% if GLOBALS.role in GLOBALS.sensor_roles %}
|
||||
{% if GLOBALS.is_sensor %}
|
||||
# Add sensor cleanup
|
||||
so-sensor-clean:
|
||||
cron.present:
|
||||
|
||||
@@ -404,6 +404,25 @@ is_single_node_grid() {
|
||||
grep "role: so-" /etc/salt/grains | grep -E "eval|standalone|import" &> /dev/null
|
||||
}
|
||||
|
||||
initialize_elasticsearch_indices() {
|
||||
local index_names=$1
|
||||
local default_entry=${2:-'{"@timestamp":"0"}'}
|
||||
|
||||
for idx in $index_names; do
|
||||
if ! so-elasticsearch-query "$idx" --fail --retry 3 --retry-delay 30 >/dev/null 2>&1; then
|
||||
echo "Index does not already exist. Initializing $idx index."
|
||||
|
||||
if retry 3 10 "so-elasticsearch-query "$idx/_doc" -d '$default_entry' -XPOST --fail 2>/dev/null" '"successful":1'; then
|
||||
echo "Successfully initialized $idx index."
|
||||
else
|
||||
echo "Failed to initialize $idx index after 3 attempts."
|
||||
fi
|
||||
else
|
||||
echo "Index $idx already exists. No action needed."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
lookup_bond_interfaces() {
|
||||
cat /proc/net/bonding/bond0 | grep "Slave Interface:" | sed -e "s/Slave Interface: //g"
|
||||
}
|
||||
@@ -554,21 +573,39 @@ run_check_net_err() {
|
||||
}
|
||||
|
||||
wait_for_salt_minion() {
|
||||
local minion="$1"
|
||||
local timeout="${2:-5}"
|
||||
local logfile="${3:-'/dev/stdout'}"
|
||||
retry 60 5 "journalctl -u salt-minion.service | grep 'Minion is ready to receive requests'" >> "$logfile" 2>&1 || fail
|
||||
local attempt=0
|
||||
# each attempts would take about 15 seconds
|
||||
local maxAttempts=20
|
||||
until check_salt_minion_status "$minion" "$timeout" "$logfile"; do
|
||||
attempt=$((attempt+1))
|
||||
if [[ $attempt -eq $maxAttempts ]]; then
|
||||
return 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
return 0
|
||||
local minion="$1"
|
||||
local max_wait="${2:-30}"
|
||||
local interval="${3:-2}"
|
||||
local logfile="${4:-'/dev/stdout'}"
|
||||
local elapsed=0
|
||||
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Waiting for salt-minion '$minion' to be ready..."
|
||||
|
||||
while [ $elapsed -lt $max_wait ]; do
|
||||
# Check if service is running
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Check if salt-minion service is running"
|
||||
if ! systemctl is-active --quiet salt-minion; then
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion service not running (elapsed: ${elapsed}s)"
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
continue
|
||||
fi
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion service is running"
|
||||
|
||||
# Check if minion responds to ping
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Check if $minion responds to ping"
|
||||
if salt "$minion" test.ping --timeout=3 --out=json 2>> "$logfile" | grep -q "true"; then
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion '$minion' is connected and ready!"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Waiting... (${elapsed}s / ${max_wait}s)"
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
done
|
||||
|
||||
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - ERROR: salt-minion '$minion' not ready after $max_wait seconds"
|
||||
return 1
|
||||
}
|
||||
|
||||
salt_minion_count() {
|
||||
|
||||
@@ -129,6 +129,8 @@ if [[ $EXCLUDE_STARTUP_ERRORS == 'Y' ]]; then
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|responded with status-code 503" # telegraf getting 503 from ES during startup
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|process_cluster_event_timeout_exception" # logstash waiting for elasticsearch to start
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|not configured for GeoIP" # SO does not bundle the maxminddb with Zeek
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|HTTP 404: Not Found" # Salt loops until Kratos returns 200, during startup Kratos may not be ready
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Cancelling deferred write event maybeFenceReplicas because the event queue is now closed" # Kafka controller log during shutdown/restart
|
||||
fi
|
||||
|
||||
if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
|
||||
@@ -159,7 +161,9 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|adding ingest pipeline" # false positive (elasticsearch ingest pipeline names contain 'error')
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating index template" # false positive (elasticsearch index or template names contain 'error')
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating component template" # false positive (elasticsearch index or template names contain 'error')
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|upgrading component template" # false positive (elasticsearch index or template names contain 'error')
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|upgrading composable template" # false positive (elasticsearch composable template names contain 'error')
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Error while parsing document for index \[.ds-logs-kratos-so-.*object mapping for \[file\]" # false positive (mapping error occuring BEFORE kratos index has rolled over in 2.4.210)
|
||||
fi
|
||||
|
||||
if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
|
||||
@@ -223,6 +227,7 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|from NIC checksum offloading" # zeek reporter.log
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|marked for removal" # docker container getting recycled
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tcp 127.0.0.1:6791: bind: address already in use" # so-elastic-fleet agent restarting. Seen starting w/ 8.18.8 https://github.com/elastic/kibana/issues/201459
|
||||
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|TransformTask\] \[logs-(tychon|aws_billing|microsoft_defender_endpoint).*user so_kibana lacks the required permissions \[logs-\1" # Known issue with 3 integrations using kibana_system role vs creating unique api creds with proper permissions.
|
||||
fi
|
||||
|
||||
RESULT=0
|
||||
|
||||
@@ -3,29 +3,16 @@
|
||||
{# we only want this state to run it is CentOS #}
|
||||
{% if GLOBALS.os == 'OEL' %}
|
||||
|
||||
{% set global_ca_text = [] %}
|
||||
{% set global_ca_server = [] %}
|
||||
{% set manager = GLOBALS.manager %}
|
||||
{% set x509dict = salt['mine.get'](manager | lower~'*', 'x509.get_pem_entries') %}
|
||||
{% for host in x509dict %}
|
||||
{% if host.split('_')|last in ['manager', 'managersearch', 'standalone', 'import', 'eval'] %}
|
||||
{% do global_ca_text.append(x509dict[host].get('/etc/pki/ca.crt')|replace('\n', '')) %}
|
||||
{% do global_ca_server.append(host) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set trusttheca_text = global_ca_text[0] %}
|
||||
{% set ca_server = global_ca_server[0] %}
|
||||
|
||||
trusted_ca:
|
||||
x509.pem_managed:
|
||||
file.managed:
|
||||
- name: /etc/pki/ca-trust/source/anchors/ca.crt
|
||||
- text: {{ trusttheca_text }}
|
||||
- source: salt://ca/files/ca.crt
|
||||
|
||||
update_ca_certs:
|
||||
cmd.run:
|
||||
- name: update-ca-trust
|
||||
- onchanges:
|
||||
- x509: trusted_ca
|
||||
- file: trusted_ca
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
|
||||
# include ssl since docker service requires the intca
|
||||
# docker service requires the ca.crt
|
||||
include:
|
||||
- ssl
|
||||
- ca
|
||||
|
||||
dockergroup:
|
||||
group.present:
|
||||
@@ -20,20 +20,20 @@ dockergroup:
|
||||
dockerheldpackages:
|
||||
pkg.installed:
|
||||
- pkgs:
|
||||
- containerd.io: 1.7.21-1
|
||||
- docker-ce: 5:27.2.0-1~debian.12~bookworm
|
||||
- docker-ce-cli: 5:27.2.0-1~debian.12~bookworm
|
||||
- docker-ce-rootless-extras: 5:27.2.0-1~debian.12~bookworm
|
||||
- containerd.io: 2.2.1-1~debian.12~bookworm
|
||||
- docker-ce: 5:29.2.1-1~debian.12~bookworm
|
||||
- docker-ce-cli: 5:29.2.1-1~debian.12~bookworm
|
||||
- docker-ce-rootless-extras: 5:29.2.1-1~debian.12~bookworm
|
||||
- hold: True
|
||||
- update_holds: True
|
||||
{% elif grains.oscodename == 'jammy' %}
|
||||
dockerheldpackages:
|
||||
pkg.installed:
|
||||
- pkgs:
|
||||
- containerd.io: 1.7.21-1
|
||||
- docker-ce: 5:27.2.0-1~ubuntu.22.04~jammy
|
||||
- docker-ce-cli: 5:27.2.0-1~ubuntu.22.04~jammy
|
||||
- docker-ce-rootless-extras: 5:27.2.0-1~ubuntu.22.04~jammy
|
||||
- containerd.io: 2.2.1-1~ubuntu.22.04~jammy
|
||||
- docker-ce: 5:29.2.1-1~ubuntu.22.04~jammy
|
||||
- docker-ce-cli: 5:29.2.1-1~ubuntu.22.04~jammy
|
||||
- docker-ce-rootless-extras: 5:29.2.1-1~ubuntu.22.04~jammy
|
||||
- hold: True
|
||||
- update_holds: True
|
||||
{% else %}
|
||||
@@ -51,10 +51,10 @@ dockerheldpackages:
|
||||
dockerheldpackages:
|
||||
pkg.installed:
|
||||
- pkgs:
|
||||
- containerd.io: 1.7.21-3.1.el9
|
||||
- docker-ce: 3:27.2.0-1.el9
|
||||
- docker-ce-cli: 1:27.2.0-1.el9
|
||||
- docker-ce-rootless-extras: 27.2.0-1.el9
|
||||
- containerd.io: 2.2.1-1.el9
|
||||
- docker-ce: 3:29.2.1-1.el9
|
||||
- docker-ce-cli: 1:29.2.1-1.el9
|
||||
- docker-ce-rootless-extras: 29.2.1-1.el9
|
||||
- hold: True
|
||||
- update_holds: True
|
||||
{% endif %}
|
||||
@@ -89,10 +89,9 @@ docker_running:
|
||||
- enable: True
|
||||
- watch:
|
||||
- file: docker_daemon
|
||||
- x509: trusttheca
|
||||
- require:
|
||||
- file: docker_daemon
|
||||
- x509: trusttheca
|
||||
- file: trusttheca
|
||||
|
||||
|
||||
# Reserve OS ports for Docker proxy in case boot settings are not already applied/present
|
||||
|
||||
@@ -60,7 +60,7 @@ so-elastalert:
|
||||
- watch:
|
||||
- file: elastaconf
|
||||
- onlyif:
|
||||
- "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #}
|
||||
- "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 9" {# only run this state if elasticsearch is version 9 #}
|
||||
|
||||
delete_so-elastalert_so-status.disabled:
|
||||
file.uncomment:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
||||
|
||||
include:
|
||||
- ca
|
||||
- elasticagent.config
|
||||
- elasticagent.sostatus
|
||||
|
||||
@@ -55,8 +56,10 @@ so-elastic-agent:
|
||||
{% endif %}
|
||||
- require:
|
||||
- file: create-elastic-agent-config
|
||||
- file: trusttheca
|
||||
- watch:
|
||||
- file: create-elastic-agent-config
|
||||
- file: trusttheca
|
||||
|
||||
delete_so-elastic-agent_so-status.disabled:
|
||||
file.uncomment:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{%- set ES_PASS = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') %}
|
||||
|
||||
id: aea1ba80-1065-11ee-a369-97538913b6a9
|
||||
revision: 1
|
||||
revision: 4
|
||||
outputs:
|
||||
default:
|
||||
type: elasticsearch
|
||||
@@ -22,242 +22,133 @@ agent:
|
||||
metrics: false
|
||||
features: {}
|
||||
inputs:
|
||||
- id: logfile-logs-fefef78c-422f-4cfa-8abf-4cd1b9428f62
|
||||
name: import-evtx-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: fefef78c-422f-4cfa-8abf-4cd1b9428f62
|
||||
streams:
|
||||
- id: logfile-log.log-fefef78c-422f-4cfa-8abf-4cd1b9428f62
|
||||
data_stream:
|
||||
dataset: import
|
||||
paths:
|
||||
- /nsm/import/*/evtx/*.json
|
||||
processors:
|
||||
- dissect:
|
||||
field: log.file.path
|
||||
tokenizer: '/nsm/import/%{import.id}/evtx/%{import.file}'
|
||||
target_prefix: ''
|
||||
- decode_json_fields:
|
||||
fields:
|
||||
- message
|
||||
target: ''
|
||||
- drop_fields:
|
||||
ignore_missing: true
|
||||
fields:
|
||||
- host
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.security
|
||||
type: logs
|
||||
namespace: default
|
||||
target: data_stream
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.security
|
||||
module: system
|
||||
imported: true
|
||||
target: event
|
||||
- then:
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: windows.sysmon_operational
|
||||
target: data_stream
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: windows.sysmon_operational
|
||||
module: windows
|
||||
imported: true
|
||||
target: event
|
||||
if:
|
||||
equals:
|
||||
winlog.channel: Microsoft-Windows-Sysmon/Operational
|
||||
- then:
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.application
|
||||
target: data_stream
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.application
|
||||
target: event
|
||||
if:
|
||||
equals:
|
||||
winlog.channel: Application
|
||||
- then:
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.system
|
||||
target: data_stream
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: system.system
|
||||
target: event
|
||||
if:
|
||||
equals:
|
||||
winlog.channel: System
|
||||
- then:
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: windows.powershell_operational
|
||||
target: data_stream
|
||||
- add_fields:
|
||||
fields:
|
||||
dataset: windows.powershell_operational
|
||||
module: windows
|
||||
target: event
|
||||
if:
|
||||
equals:
|
||||
winlog.channel: Microsoft-Windows-PowerShell/Operational
|
||||
tags:
|
||||
- import
|
||||
- id: logfile-redis-fc98c947-7d17-4861-a318-7ad075f6d1b0
|
||||
name: redis-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: redis
|
||||
version:
|
||||
data_stream:
|
||||
namespace: default
|
||||
package_policy_id: fc98c947-7d17-4861-a318-7ad075f6d1b0
|
||||
streams:
|
||||
- id: logfile-redis.log-fc98c947-7d17-4861-a318-7ad075f6d1b0
|
||||
data_stream:
|
||||
dataset: redis.log
|
||||
type: logs
|
||||
exclude_files:
|
||||
- .gz$
|
||||
paths:
|
||||
- /opt/so/log/redis/redis.log
|
||||
tags:
|
||||
- redis-log
|
||||
exclude_lines:
|
||||
- '^\s+[\-`(''.|_]'
|
||||
- id: logfile-logs-3b56803d-5ade-4c93-b25e-9b37182f66b8
|
||||
- id: filestream-filestream-85820eb0-25ef-11f0-a18d-1b26f69b8310
|
||||
name: import-suricata-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
revision: 3
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 3b56803d-5ade-4c93-b25e-9b37182f66b8
|
||||
package_policy_id: 85820eb0-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-3b56803d-5ade-4c93-b25e-9b37182f66b8
|
||||
- id: filestream-filestream.generic-85820eb0-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: import
|
||||
pipeline: suricata.common
|
||||
paths:
|
||||
- /nsm/import/*/suricata/eve*.json
|
||||
pipeline: suricata.common
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- \.gz$
|
||||
ignore_older: 72h
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- add_fields:
|
||||
target: event
|
||||
fields:
|
||||
category: network
|
||||
module: suricata
|
||||
imported: true
|
||||
category: network
|
||||
target: event
|
||||
- dissect:
|
||||
tokenizer: /nsm/import/%{import.id}/suricata/%{import.file}
|
||||
field: log.file.path
|
||||
tokenizer: '/nsm/import/%{import.id}/suricata/%{import.file}'
|
||||
target_prefix: ''
|
||||
- id: logfile-logs-c327e1a3-1ebe-449c-a8eb-f6f35032e69d
|
||||
name: soc-server-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: filestream-filestream-86b4e960-25ef-11f0-a18d-1b26f69b8310
|
||||
name: import-zeek-logs
|
||||
revision: 3
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: c327e1a3-1ebe-449c-a8eb-f6f35032e69d
|
||||
package_policy_id: 86b4e960-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-c327e1a3-1ebe-449c-a8eb-f6f35032e69d
|
||||
- id: filestream-filestream.generic-86b4e960-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: soc
|
||||
pipeline: common
|
||||
dataset: import
|
||||
paths:
|
||||
- /opt/so/log/soc/sensoroni-server.log
|
||||
- /nsm/import/*/zeek/logs/*.log
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- >-
|
||||
(broker|capture_loss|cluster|conn-summary|console|ecat_arp_info|known_certs|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout).log$
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- decode_json_fields:
|
||||
add_error_key: true
|
||||
process_array: true
|
||||
max_depth: 2
|
||||
fields:
|
||||
- message
|
||||
target: soc
|
||||
- dissect:
|
||||
tokenizer: /nsm/import/%{import.id}/zeek/logs/%{import.file}
|
||||
field: log.file.path
|
||||
target_prefix: ''
|
||||
- script:
|
||||
lang: javascript
|
||||
source: |
|
||||
function process(event) {
|
||||
var pl = event.Get("import.file").slice(0,-4);
|
||||
event.Put("@metadata.pipeline", "zeek." + pl);
|
||||
}
|
||||
- add_fields:
|
||||
fields:
|
||||
module: soc
|
||||
dataset_temp: server
|
||||
category: host
|
||||
target: event
|
||||
- rename:
|
||||
ignore_missing: true
|
||||
fields:
|
||||
- from: soc.fields.sourceIp
|
||||
to: source.ip
|
||||
- from: soc.fields.status
|
||||
to: http.response.status_code
|
||||
- from: soc.fields.method
|
||||
to: http.request.method
|
||||
- from: soc.fields.path
|
||||
to: url.path
|
||||
- from: soc.message
|
||||
to: event.action
|
||||
- from: soc.level
|
||||
to: log.level
|
||||
tags:
|
||||
- so-soc
|
||||
- id: logfile-logs-906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
|
||||
category: network
|
||||
module: zeek
|
||||
imported: true
|
||||
- add_tags:
|
||||
tags: ics
|
||||
when:
|
||||
regexp:
|
||||
import.file: >-
|
||||
^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: filestream-filestream-91741240-25ef-11f0-a18d-1b26f69b8310
|
||||
name: soc-sensoroni-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
revision: 3
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
|
||||
package_policy_id: 91741240-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
|
||||
- id: filestream-filestream.generic-91741240-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: soc
|
||||
pipeline: common
|
||||
paths:
|
||||
- /opt/so/log/sensoroni/sensoroni.log
|
||||
pipeline: common
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- \.gz$
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- decode_json_fields:
|
||||
add_error_key: true
|
||||
process_array: true
|
||||
max_depth: 2
|
||||
fields:
|
||||
- message
|
||||
target: sensoroni
|
||||
process_array: true
|
||||
max_depth: 2
|
||||
add_error_key: true
|
||||
- add_fields:
|
||||
target: event
|
||||
fields:
|
||||
category: host
|
||||
module: soc
|
||||
dataset_temp: sensoroni
|
||||
category: host
|
||||
target: event
|
||||
- rename:
|
||||
ignore_missing: true
|
||||
fields:
|
||||
- from: sensoroni.fields.sourceIp
|
||||
to: source.ip
|
||||
@@ -271,141 +162,100 @@ inputs:
|
||||
to: event.action
|
||||
- from: sensoroni.level
|
||||
to: log.level
|
||||
- id: logfile-logs-df0d7f2c-221f-433b-b18b-d1cf83250515
|
||||
name: soc-salt-relay-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: df0d7f2c-221f-433b-b18b-d1cf83250515
|
||||
streams:
|
||||
- id: logfile-log.log-df0d7f2c-221f-433b-b18b-d1cf83250515
|
||||
data_stream:
|
||||
dataset: soc
|
||||
pipeline: common
|
||||
paths:
|
||||
- /opt/so/log/soc/salt-relay.log
|
||||
processors:
|
||||
- dissect:
|
||||
field: message
|
||||
tokenizer: '%{soc.ts} | %{event.action}'
|
||||
target_prefix: ''
|
||||
- add_fields:
|
||||
fields:
|
||||
module: soc
|
||||
dataset_temp: salt_relay
|
||||
category: host
|
||||
target: event
|
||||
tags:
|
||||
- so-soc
|
||||
- id: logfile-logs-74bd2366-fe52-493c-bddc-843a017fc4d0
|
||||
name: soc-auth-sync-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 74bd2366-fe52-493c-bddc-843a017fc4d0
|
||||
streams:
|
||||
- id: logfile-log.log-74bd2366-fe52-493c-bddc-843a017fc4d0
|
||||
data_stream:
|
||||
dataset: soc
|
||||
pipeline: common
|
||||
paths:
|
||||
- /opt/so/log/soc/sync.log
|
||||
processors:
|
||||
- dissect:
|
||||
field: message
|
||||
tokenizer: '%{event.action}'
|
||||
target_prefix: ''
|
||||
- add_fields:
|
||||
fields:
|
||||
module: soc
|
||||
dataset_temp: auth_sync
|
||||
category: host
|
||||
target: event
|
||||
tags:
|
||||
- so-soc
|
||||
- id: logfile-logs-d151d9bf-ff2a-4529-9520-c99244bc0253
|
||||
ignore_missing: true
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: filestream-filestream-976e3900-25ef-11f0-a18d-1b26f69b8310
|
||||
name: suricata-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
revision: 3
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: d151d9bf-ff2a-4529-9520-c99244bc0253
|
||||
package_policy_id: 976e3900-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-d151d9bf-ff2a-4529-9520-c99244bc0253
|
||||
- id: filestream-filestream.generic-976e3900-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: suricata
|
||||
pipeline: suricata.common
|
||||
paths:
|
||||
- /nsm/suricata/eve*.json
|
||||
pipeline: suricata.common
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- \.gz$
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- add_fields:
|
||||
fields:
|
||||
module: suricata
|
||||
category: network
|
||||
target: event
|
||||
- id: logfile-logs-31f94d05-ae75-40ee-b9c5-0e0356eff327
|
||||
fields:
|
||||
category: network
|
||||
module: suricata
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: filestream-filestream-95091fe0-25ef-11f0-a18d-1b26f69b8310
|
||||
name: strelka-logs
|
||||
revision: 2
|
||||
type: logfile
|
||||
revision: 3
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 31f94d05-ae75-40ee-b9c5-0e0356eff327
|
||||
package_policy_id: 95091fe0-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-31f94d05-ae75-40ee-b9c5-0e0356eff327
|
||||
- id: filestream-filestream.generic-95091fe0-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: strelka
|
||||
pipeline: strelka.file
|
||||
paths:
|
||||
- /nsm/strelka/log/strelka.log
|
||||
pipeline: strelka.file
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- \.gz$
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- add_fields:
|
||||
fields:
|
||||
module: strelka
|
||||
category: file
|
||||
target: event
|
||||
- id: logfile-logs-6197fe84-9b58-4d9b-8464-3d517f28808d
|
||||
fields:
|
||||
category: file
|
||||
module: strelka
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: filestream-filestream-9f309ca0-25ef-11f0-a18d-1b26f69b8310
|
||||
name: zeek-logs
|
||||
revision: 1
|
||||
type: logfile
|
||||
revision: 2
|
||||
type: filestream
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: log
|
||||
version:
|
||||
name: filestream
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 6197fe84-9b58-4d9b-8464-3d517f28808d
|
||||
package_policy_id: 9f309ca0-25ef-11f0-a18d-1b26f69b8310
|
||||
streams:
|
||||
- id: logfile-log.log-6197fe84-9b58-4d9b-8464-3d517f28808d
|
||||
- id: filestream-filestream.generic-9f309ca0-25ef-11f0-a18d-1b26f69b8310
|
||||
data_stream:
|
||||
dataset: zeek
|
||||
paths:
|
||||
- /nsm/zeek/logs/current/*.log
|
||||
prospector.scanner.recursive_glob: true
|
||||
prospector.scanner.exclude_files:
|
||||
- >-
|
||||
(broker|capture_loss|cluster|conn-summary|console|ecat_arp_info|known_certs|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout).log$
|
||||
clean_inactive: -1
|
||||
parsers: null
|
||||
processors:
|
||||
- dissect:
|
||||
tokenizer: '/nsm/zeek/logs/current/%{pipeline}.log'
|
||||
tokenizer: /nsm/zeek/logs/current/%{pipeline}.log
|
||||
field: log.file.path
|
||||
trim_chars: .log
|
||||
target_prefix: ''
|
||||
@@ -427,18 +277,17 @@ inputs:
|
||||
regexp:
|
||||
pipeline: >-
|
||||
^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*
|
||||
exclude_files:
|
||||
- >-
|
||||
broker|capture_loss|cluster|ecat_arp_info|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout.log$
|
||||
file_identity.native: null
|
||||
prospector.scanner.fingerprint.enabled: false
|
||||
- id: udp-udp-35051de0-46a5-11ee-8d5d-9f98c8182f60
|
||||
name: syslog-udp-514
|
||||
revision: 3
|
||||
revision: 4
|
||||
type: udp
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: udp
|
||||
version: 1.10.0
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 35051de0-46a5-11ee-8d5d-9f98c8182f60
|
||||
@@ -458,13 +307,13 @@ inputs:
|
||||
- syslog
|
||||
- id: tcp-tcp-33d37bb0-46a5-11ee-8d5d-9f98c8182f60
|
||||
name: syslog-tcp-514
|
||||
revision: 3
|
||||
revision: 4
|
||||
type: tcp
|
||||
use_output: default
|
||||
meta:
|
||||
package:
|
||||
name: tcp
|
||||
version: 1.10.0
|
||||
version:
|
||||
data_stream:
|
||||
namespace: so
|
||||
package_policy_id: 33d37bb0-46a5-11ee-8d5d-9f98c8182f60
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
include:
|
||||
- elasticfleet.artifact_registry
|
||||
- elasticfleet.ssl
|
||||
|
||||
# Add EA Group
|
||||
elasticfleetgroup:
|
||||
@@ -95,6 +96,9 @@ soresourcesrepoclone:
|
||||
- rev: 'main'
|
||||
- depth: 1
|
||||
- force_reset: True
|
||||
- retry:
|
||||
attempts: 3
|
||||
interval: 10
|
||||
{% endif %}
|
||||
|
||||
elasticdefendconfdir:
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
{% set SERVICETOKEN = salt['pillar.get']('elasticfleet:config:server:es_token','') %}
|
||||
|
||||
include:
|
||||
- ca
|
||||
- logstash.ssl
|
||||
- elasticfleet.config
|
||||
- elasticfleet.sostatus
|
||||
- ssl
|
||||
|
||||
{% if grains.role not in ['so-fleet'] %}
|
||||
# Wait for Elasticsearch to be ready - no reason to try running Elastic Fleet server if ES is not ready
|
||||
@@ -133,6 +134,11 @@ so-elastic-fleet:
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- watch:
|
||||
- file: trusttheca
|
||||
- x509: etc_elasticfleet_key
|
||||
- x509: etc_elasticfleet_crt
|
||||
- require:
|
||||
- file: trusttheca
|
||||
- x509: etc_elasticfleet_key
|
||||
- x509: etc_elasticfleet_crt
|
||||
{% endif %}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{%- raw -%}
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "import-zeek-logs",
|
||||
@@ -10,19 +10,31 @@
|
||||
"description": "Zeek Import logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/import/*/zeek/logs/*.log"
|
||||
],
|
||||
"data_stream.dataset": "import",
|
||||
"tags": [],
|
||||
"pipeline": "",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": ["({%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%})(\\..+)?\\.log$"],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/zeek/logs/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"import.file\").slice(0,-4);\n event.Put(\"@metadata.pipeline\", \"zeek.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: zeek\n imported: true\n- add_tags:\n tags: \"ics\"\n when:\n regexp:\n import.file: \"^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*\"",
|
||||
"custom": "exclude_files: [\"{%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%}.log$\"]\n"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,36 +11,51 @@
|
||||
{%- endif -%}
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "kratos-logs",
|
||||
"namespace": "so",
|
||||
"description": "Kratos logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/kratos/kratos.log"
|
||||
],
|
||||
"data_stream.dataset": "kratos",
|
||||
"tags": ["so-kratos"],
|
||||
"pipeline": "kratos",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
{%- if valid_identities -%}
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: kratos\n- if:\n has_fields:\n - identity_id\n then:{% for id, email in identities %}\n - if:\n equals:\n identity_id: \"{{ id }}\"\n then:\n - add_fields:\n target: ''\n fields:\n user.name: \"{{ email }}\"{% endfor %}",
|
||||
{%- else -%}
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: kratos",
|
||||
{%- endif -%}
|
||||
"custom": "pipeline: kratos"
|
||||
"tags": [
|
||||
"so-kratos"
|
||||
],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,28 +2,38 @@
|
||||
{%- raw -%}
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"id": "zeek-logs",
|
||||
"name": "zeek-logs",
|
||||
"namespace": "so",
|
||||
"description": "Zeek logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/zeek/logs/current/*.log"
|
||||
],
|
||||
"data_stream.dataset": "zeek",
|
||||
"tags": [],
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": ["({%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%})(\\..+)?\\.log$"],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"/nsm/zeek/logs/current/%{pipeline}.log\"\n field: \"log.file.path\"\n trim_chars: \".log\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"pipeline\");\n event.Put(\"@metadata.pipeline\", \"zeek.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: zeek\n- add_tags:\n tags: \"ics\"\n when:\n regexp:\n pipeline: \"^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*\"",
|
||||
"custom": "exclude_files: [\"{%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%}.log$\"]\n"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,4 +41,4 @@
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
{%- endraw -%}
|
||||
{%- endraw -%}
|
||||
@@ -5,7 +5,7 @@
|
||||
"package": {
|
||||
"name": "endpoint",
|
||||
"title": "Elastic Defend",
|
||||
"version": "8.18.1",
|
||||
"version": "9.0.2",
|
||||
"requires_root": true
|
||||
},
|
||||
"enabled": true,
|
||||
|
||||
@@ -1,26 +1,43 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "hydra-logs",
|
||||
"namespace": "so",
|
||||
"description": "Hydra logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/hydra/hydra.log"
|
||||
],
|
||||
"data_stream.dataset": "hydra",
|
||||
"tags": ["so-hydra"],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: iam\n module: hydra",
|
||||
"custom": "pipeline: hydra"
|
||||
"pipeline": "hydra",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: hydra",
|
||||
"tags": [
|
||||
"so-hydra"
|
||||
],
|
||||
"recursive_glob": true,
|
||||
"ignore_older": "72h",
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,3 +45,5 @@
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +1,44 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "idh-logs",
|
||||
"namespace": "so",
|
||||
"description": "IDH integration",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/idh/opencanary.log"
|
||||
],
|
||||
"data_stream.dataset": "idh",
|
||||
"tags": [],
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- convert:\n fields:\n - {from: \"logtype\", to: \"event.code\", type: \"string\"}\n- drop_fields:\n when:\n equals:\n event.code: \"1001\"\n fields: [\"src_host\", \"src_port\", \"dst_host\", \"dst_port\" ]\n ignore_missing: true\n- rename:\n fields:\n - from: \"src_host\"\n to: \"source.ip\"\n - from: \"src_port\"\n to: \"source.port\"\n - from: \"dst_host\"\n to: \"destination.host\"\n - from: \"dst_port\"\n to: \"destination.port\"\n ignore_missing: true\n- drop_fields:\n fields: '[\"prospector\", \"input\", \"offset\", \"beat\"]'\n- add_fields:\n target: event\n fields:\n category: host\n module: opencanary",
|
||||
"custom": "pipeline: common"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,46 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "import-evtx-logs",
|
||||
"namespace": "so",
|
||||
"description": "Import Windows EVTX logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"vars": {},
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/import/*/evtx/*.json"
|
||||
],
|
||||
"data_stream.dataset": "import",
|
||||
"custom": "",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.6.1\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.1.2\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.6.1\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.6.1\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.1.2\n- add_fields:\n target: data_stream\n fields:\n dataset: import",
|
||||
"tags": [
|
||||
"import"
|
||||
]
|
||||
],
|
||||
"recursive_glob": true,
|
||||
"ignore_older": "72h",
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,45 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "import-suricata-logs",
|
||||
"namespace": "so",
|
||||
"description": "Import Suricata logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/import/*/suricata/eve*.json"
|
||||
],
|
||||
"data_stream.dataset": "import",
|
||||
"pipeline": "suricata.common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata\n imported: true\n- dissect:\n tokenizer: \"/nsm/import/%{import.id}/suricata/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n",
|
||||
"tags": [],
|
||||
"processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata\n imported: true\n- dissect:\n tokenizer: \"/nsm/import/%{import.id}/suricata/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"",
|
||||
"custom": "pipeline: suricata.common"
|
||||
"recursive_glob": true,
|
||||
"ignore_older": "72h",
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/redis/redis.log"
|
||||
"/opt/so/log/redis/redis-server.log"
|
||||
],
|
||||
"tags": [
|
||||
"redis-log"
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "rita-logs",
|
||||
"namespace": "so",
|
||||
"description": "RITA Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"vars": {},
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
@@ -20,15 +19,28 @@
|
||||
"/nsm/rita/exploded-dns.csv",
|
||||
"/nsm/rita/long-connections.csv"
|
||||
],
|
||||
"exclude_files": [],
|
||||
"ignore_older": "72h",
|
||||
"data_stream.dataset": "rita",
|
||||
"tags": [],
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"/nsm/rita/%{pipeline}.csv\"\n field: \"log.file.path\"\n trim_chars: \".csv\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"pipeline\").split(\"-\");\n if (pl.length > 1) {\n pl = pl[1];\n }\n else {\n pl = pl[0];\n }\n event.Put(\"@metadata.pipeline\", \"rita.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: rita",
|
||||
"custom": "exclude_lines: ['^Score', '^Source', '^Domain', '^No results']"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"ignore_older": "72h",
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
|
||||
@@ -1,29 +1,41 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "so-ip-mappings",
|
||||
"namespace": "so",
|
||||
"description": "IP Description mappings",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"vars": {},
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/custom-mappings/ip-descriptions.csv"
|
||||
],
|
||||
"data_stream.dataset": "hostnamemappings",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- decode_csv_fields:\n fields:\n message: decoded.csv\n separator: \",\"\n ignore_missing: false\n overwrite_keys: true\n trim_leading_space: true\n fail_on_error: true\n\n- extract_array:\n field: decoded.csv\n mappings:\n so.ip_address: '0'\n so.description: '1'\n\n- script:\n lang: javascript\n source: >\n function process(event) {\n var ip = event.Get('so.ip_address');\n var validIpRegex = /^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/\n if (!validIpRegex.test(ip)) {\n event.Cancel();\n }\n }\n- fingerprint:\n fields: [\"so.ip_address\"]\n target_field: \"@metadata._id\"\n",
|
||||
"tags": [
|
||||
"so-ip-mappings"
|
||||
],
|
||||
"processors": "- decode_csv_fields:\n fields:\n message: decoded.csv\n separator: \",\"\n ignore_missing: false\n overwrite_keys: true\n trim_leading_space: true\n fail_on_error: true\n\n- extract_array:\n field: decoded.csv\n mappings:\n so.ip_address: '0'\n so.description: '1'\n\n- script:\n lang: javascript\n source: >\n function process(event) {\n var ip = event.Get('so.ip_address');\n var validIpRegex = /^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/\n if (!validIpRegex.test(ip)) {\n event.Cancel();\n }\n }\n- fingerprint:\n fields: [\"so.ip_address\"]\n target_field: \"@metadata._id\"\n",
|
||||
"custom": ""
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,5 +43,3 @@
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +1,44 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "soc-auth-sync-logs",
|
||||
"namespace": "so",
|
||||
"description": "Security Onion - Elastic Auth Sync - Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/soc/sync.log"
|
||||
],
|
||||
"data_stream.dataset": "soc",
|
||||
"tags": ["so-soc"],
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"%{event.action}\"\n field: \"message\"\n target_prefix: \"\"\n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: auth_sync",
|
||||
"custom": "pipeline: common"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,48 @@
|
||||
{
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "soc-detections-logs",
|
||||
"description": "Security Onion Console - Detections Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/soc/detections_runtime-status_sigma.log",
|
||||
"/opt/so/log/soc/detections_runtime-status_yara.log"
|
||||
],
|
||||
"exclude_files": [],
|
||||
"ignore_older": "72h",
|
||||
"data_stream.dataset": "soc",
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: detections\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true",
|
||||
"tags": [
|
||||
"so-soc"
|
||||
],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: detections\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true",
|
||||
"custom": "pipeline: common"
|
||||
"recursive_glob": true,
|
||||
"ignore_older": "72h",
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,46 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "soc-salt-relay-logs",
|
||||
"namespace": "so",
|
||||
"description": "Security Onion - Salt Relay - Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/soc/salt-relay.log"
|
||||
],
|
||||
"data_stream.dataset": "soc",
|
||||
"tags": ["so-soc"],
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- dissect:\n tokenizer: \"%{soc.ts} | %{event.action}\"\n field: \"message\"\n target_prefix: \"\"\n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: salt_relay",
|
||||
"custom": "pipeline: common"
|
||||
"tags": [
|
||||
"so-soc"
|
||||
],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,44 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "soc-sensoroni-logs",
|
||||
"namespace": "so",
|
||||
"description": "Security Onion - Sensoroni - Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/sensoroni/sensoroni.log"
|
||||
],
|
||||
"data_stream.dataset": "soc",
|
||||
"tags": [],
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"sensoroni\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: sensoroni\n- rename:\n fields:\n - from: \"sensoroni.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"sensoroni.fields.status\"\n to: \"http.response.status_code\"\n - from: \"sensoroni.fields.method\"\n to: \"http.request.method\"\n - from: \"sensoroni.fields.path\"\n to: \"url.path\"\n - from: \"sensoroni.message\"\n to: \"event.action\"\n - from: \"sensoroni.level\"\n to: \"log.level\"\n ignore_missing: true",
|
||||
"custom": "pipeline: common"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
"force": true
|
||||
}
|
||||
@@ -1,30 +1,46 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "soc-server-logs",
|
||||
"namespace": "so",
|
||||
"description": "Security Onion Console Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/soc/sensoroni-server.log"
|
||||
],
|
||||
"data_stream.dataset": "soc",
|
||||
"tags": ["so-soc"],
|
||||
"pipeline": "common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: server\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true",
|
||||
"custom": "pipeline: common"
|
||||
"tags": [
|
||||
"so-soc"
|
||||
],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,44 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "strelka-logs",
|
||||
"namespace": "so",
|
||||
"description": "Strelka logs",
|
||||
"description": "Strelka Logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/strelka/log/strelka.log"
|
||||
],
|
||||
"data_stream.dataset": "strelka",
|
||||
"tags": [],
|
||||
"pipeline": "strelka.file",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- add_fields:\n target: event\n fields:\n category: file\n module: strelka",
|
||||
"custom": "pipeline: strelka.file"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,44 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"name": "filestream",
|
||||
"version": ""
|
||||
},
|
||||
"name": "suricata-logs",
|
||||
"namespace": "so",
|
||||
"description": "Suricata integration",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"namespace": "so",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"filestream-filestream": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"filestream.generic": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/nsm/suricata/eve*.json"
|
||||
],
|
||||
"data_stream.dataset": "suricata",
|
||||
"tags": [],
|
||||
"data_stream.dataset": "filestream.generic",
|
||||
"pipeline": "suricata.common",
|
||||
"parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n",
|
||||
"exclude_files": [
|
||||
"\\.gz$"
|
||||
],
|
||||
"include_files": [],
|
||||
"processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata",
|
||||
"custom": "pipeline: suricata.common"
|
||||
"tags": [],
|
||||
"recursive_glob": true,
|
||||
"clean_inactive": -1,
|
||||
"harvester_limit": 0,
|
||||
"fingerprint": false,
|
||||
"fingerprint_offset": 0,
|
||||
"fingerprint_length": "64",
|
||||
"file_identity_native": true,
|
||||
"exclude_lines": [],
|
||||
"include_lines": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "elasticsearch",
|
||||
"version": ""
|
||||
},
|
||||
"name": "elasticsearch-grid-nodes_heavy",
|
||||
"namespace": "default",
|
||||
"description": "Elasticsearch Logs",
|
||||
"policy_id": "so-grid-nodes_heavy",
|
||||
"inputs": {
|
||||
"elasticsearch-logfile": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"elasticsearch.audit": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/var/log/elasticsearch/*_audit.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"elasticsearch.deprecation": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/var/log/elasticsearch/*_deprecation.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"elasticsearch.gc": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/var/log/elasticsearch/gc.log.[0-9]*",
|
||||
"/var/log/elasticsearch/gc.log"
|
||||
]
|
||||
}
|
||||
},
|
||||
"elasticsearch.server": {
|
||||
"enabled": true,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/opt/so/log/elasticsearch/*.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"elasticsearch.slowlog": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"paths": [
|
||||
"/var/log/elasticsearch/*_index_search_slowlog.json",
|
||||
"/var/log/elasticsearch/*_index_indexing_slowlog.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"elasticsearch-elasticsearch/metrics": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"hosts": [
|
||||
"http://localhost:9200"
|
||||
],
|
||||
"scope": "node"
|
||||
},
|
||||
"streams": {
|
||||
"elasticsearch.stack_monitoring.ccr": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.cluster_stats": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.enrich": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.index": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.index_recovery": {
|
||||
"enabled": false,
|
||||
"vars": {
|
||||
"active.only": true
|
||||
}
|
||||
},
|
||||
"elasticsearch.stack_monitoring.index_summary": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.ml_job": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.node": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.node_stats": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.pending_tasks": {
|
||||
"enabled": false
|
||||
},
|
||||
"elasticsearch.stack_monitoring.shard": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
@@ -8,7 +8,9 @@
|
||||
{% endif %}
|
||||
|
||||
{% set AGENT_STATUS = salt['service.available']('elastic-agent') %}
|
||||
{% if not AGENT_STATUS %}
|
||||
{% set AGENT_EXISTS = salt['file.file_exists']('/opt/Elastic/Agent/elastic-agent') %}
|
||||
|
||||
{% if not AGENT_STATUS or not AGENT_EXISTS %}
|
||||
|
||||
pull_agent_installer:
|
||||
file.managed:
|
||||
@@ -19,7 +21,7 @@ pull_agent_installer:
|
||||
|
||||
run_installer:
|
||||
cmd.run:
|
||||
- name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }}
|
||||
- name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }} -force
|
||||
- cwd: /opt/so
|
||||
- retry:
|
||||
attempts: 3
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
'azure_application_insights.app_state': 'azure.app_state',
|
||||
'azure_billing.billing': 'azure.billing',
|
||||
'azure_functions.metrics': 'azure.function',
|
||||
'azure_ai_foundry.metrics': 'azure.ai_foundry',
|
||||
'azure_metrics.compute_vm_scaleset': 'azure.compute_vm_scaleset',
|
||||
'azure_metrics.compute_vm': 'azure.compute_vm',
|
||||
'azure_metrics.container_instance': 'azure.container_instance',
|
||||
|
||||
186
salt/elasticfleet/ssl.sls
Normal file
186
salt/elasticfleet/ssl.sls
Normal file
@@ -0,0 +1,186 @@
|
||||
# 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 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||
{% from 'ca/map.jinja' import CA %}
|
||||
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %}
|
||||
|
||||
{% if grains['role'] not in [ 'so-heavynode', 'so-receiver'] %}
|
||||
# Start -- Elastic Fleet Host Cert
|
||||
etc_elasticfleet_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticfleet-server.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticfleet-server.key') -%}
|
||||
- prereq:
|
||||
- x509: etc_elasticfleet_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
etc_elasticfleet_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticfleet-server.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: elasticfleet
|
||||
- private_key: /etc/pki/elasticfleet-server.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
efperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-server.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetcrt:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-server.crt
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetkey:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-server.key
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
# End -- Elastic Fleet Host Cert
|
||||
{% endif %} # endif is for not including HeavyNodes & Receivers
|
||||
|
||||
|
||||
# Start -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output)
|
||||
etc_elasticfleet_agent_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticfleet-agent.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticfleet-agent.key') -%}
|
||||
- prereq:
|
||||
- x509: etc_elasticfleet_agent_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
etc_elasticfleet_agent_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticfleet-agent.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: elasticfleet
|
||||
- private_key: /etc/pki/elasticfleet-agent.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-agent.key -topk8 -out /etc/pki/elasticfleet-agent.p8 -nocrypt"
|
||||
- onchanges:
|
||||
- x509: etc_elasticfleet_agent_key
|
||||
|
||||
efagentperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-agent.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetagentcrt:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-agent.crt
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetagentkey:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-agent.key
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
# End -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output)
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone'] %}
|
||||
elasticfleet_kafka_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticfleet-kafka.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticfleet-kafka.key') -%}
|
||||
- prereq:
|
||||
- x509: elasticfleet_kafka_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
elasticfleet_kafka_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticfleet-kafka.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: kafka
|
||||
- private_key: /etc/pki/elasticfleet-kafka.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
elasticfleet_kafka_cert_perms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-kafka.crt
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
|
||||
elasticfleet_kafka_key_perms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-kafka.key
|
||||
- mode: 640
|
||||
- user: 947
|
||||
- group: 939
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -17,9 +17,9 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
|
||||
|
||||
# Third, configure Elastic Defend Integration seperately
|
||||
/usr/sbin/so-elastic-fleet-integration-policy-elastic-defend
|
||||
|
||||
# Initial Endpoints
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/endpoints-initial/*.json
|
||||
do
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/endpoints-initial/*.json; do
|
||||
printf "\n\nInitial Endpoints Policy - Loading $INTEGRATION\n"
|
||||
elastic_fleet_integration_check "endpoints-initial" "$INTEGRATION"
|
||||
if [ -n "$INTEGRATION_ID" ]; then
|
||||
@@ -40,8 +40,7 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
|
||||
done
|
||||
|
||||
# Grid Nodes - General
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_general/*.json
|
||||
do
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_general/*.json; do
|
||||
printf "\n\nGrid Nodes Policy_General - Loading $INTEGRATION\n"
|
||||
elastic_fleet_integration_check "so-grid-nodes_general" "$INTEGRATION"
|
||||
if [ -n "$INTEGRATION_ID" ]; then
|
||||
@@ -60,13 +59,9 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ "$RETURN_CODE" != "1" ]]; then
|
||||
touch /opt/so/state/eaintegrations.txt
|
||||
fi
|
||||
|
||||
# Grid Nodes - Heavy
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_heavy/*.json
|
||||
do
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_heavy/*.json; do
|
||||
printf "\n\nGrid Nodes Policy_Heavy - Loading $INTEGRATION\n"
|
||||
elastic_fleet_integration_check "so-grid-nodes_heavy" "$INTEGRATION"
|
||||
if [ -n "$INTEGRATION_ID" ]; then
|
||||
@@ -78,22 +73,16 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
|
||||
fi
|
||||
else
|
||||
printf "\n\nIntegration does not exist - Creating integration\n"
|
||||
if [ "$NAME" != "elasticsearch-logs" ]; then
|
||||
if ! elastic_fleet_integration_create "@$INTEGRATION"; then
|
||||
echo -e "\nFailed to create integration for ${INTEGRATION##*/}"
|
||||
RETURN_CODE=1
|
||||
continue
|
||||
fi
|
||||
if ! elastic_fleet_integration_create "@$INTEGRATION"; then
|
||||
echo -e "\nFailed to create integration for ${INTEGRATION##*/}"
|
||||
RETURN_CODE=1
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ "$RETURN_CODE" != "1" ]]; then
|
||||
touch /opt/so/state/eaintegrations.txt
|
||||
fi
|
||||
|
||||
# Fleet Server - Optional integrations
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json
|
||||
do
|
||||
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json; do
|
||||
if ! [ "$INTEGRATION" == "/opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json" ]; then
|
||||
FLEET_POLICY=`echo "$INTEGRATION"| cut -d'/' -f7`
|
||||
printf "\n\nFleet Server Policy - Loading $INTEGRATION\n"
|
||||
@@ -117,6 +106,8 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Only create the state file if all policies were created/updated successfully
|
||||
if [[ "$RETURN_CODE" != "1" ]]; then
|
||||
touch /opt/so/state/eaintegrations.txt
|
||||
fi
|
||||
|
||||
@@ -14,7 +14,7 @@ if ! is_manager_node; then
|
||||
fi
|
||||
|
||||
# Get current list of Grid Node Agents that need to be upgraded
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/agents?perPage=20&page=1&kuery=NOT%20agent.version%20:%20%22{{ELASTICSEARCHDEFAULTS.elasticsearch.version}}%22%20and%20policy_id%20:%20%22so-grid-nodes_general%22&showInactive=false&getStatusSummary=true")
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/agents?perPage=20&page=1&kuery=NOT%20agent.version%3A%20{{ELASTICSEARCHDEFAULTS.elasticsearch.version}}%20AND%20policy_id%3A%20so-grid-nodes_%2A&showInactive=false&getStatusSummary=true" --retry 3 --retry-delay 30 --fail 2>/dev/null)
|
||||
|
||||
# Check to make sure that the server responded with good data - else, bail from script
|
||||
CHECKSUM=$(jq -r '.page' <<< "$RAW_JSON")
|
||||
|
||||
@@ -26,7 +26,7 @@ function update_es_urls() {
|
||||
}
|
||||
|
||||
# Get current list of Fleet Elasticsearch URLs
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch')
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch' --retry 3 --retry-delay 30 --fail 2>/dev/null)
|
||||
|
||||
# Check to make sure that the server responded with good data - else, bail from script
|
||||
CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON")
|
||||
|
||||
@@ -86,7 +86,7 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then
|
||||
latest_package_list=$(/usr/sbin/so-elastic-fleet-package-list)
|
||||
echo '{ "packages" : []}' > $BULK_INSTALL_PACKAGE_LIST
|
||||
rm -f $INSTALLED_PACKAGE_LIST
|
||||
echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .savedObject.attributes.install_version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST
|
||||
echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .installationInfo.version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST
|
||||
|
||||
while read -r package; do
|
||||
# get package details
|
||||
|
||||
@@ -142,7 +142,7 @@ function update_kafka_outputs() {
|
||||
|
||||
{% if GLOBALS.pipeline == "KAFKA" %}
|
||||
# Get current list of Kafka Outputs
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_kafka')
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_kafka' --retry 3 --retry-delay 30 --fail 2>/dev/null)
|
||||
|
||||
# Check to make sure that the server responded with good data - else, bail from script
|
||||
CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON")
|
||||
@@ -168,7 +168,7 @@ function update_kafka_outputs() {
|
||||
{# If global pipeline isn't set to KAFKA then assume default of REDIS / logstash #}
|
||||
{% else %}
|
||||
# Get current list of Logstash Outputs
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_logstash')
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_logstash' --retry 3 --retry-delay 30 --fail 2>/dev/null)
|
||||
|
||||
# Check to make sure that the server responded with good data - else, bail from script
|
||||
CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON")
|
||||
|
||||
@@ -241,9 +241,11 @@ printf '%s\n'\
|
||||
"" >> "$global_pillar_file"
|
||||
|
||||
# Call Elastic-Fleet Salt State
|
||||
printf "\nApplying elasticfleet state"
|
||||
salt-call state.apply elasticfleet queue=True
|
||||
|
||||
# Generate installers & install Elastic Agent on the node
|
||||
so-elastic-agent-gen-installers
|
||||
printf "\nApplying elasticfleet.install_agent_grid state"
|
||||
salt-call state.apply elasticfleet.install_agent_grid queue=True
|
||||
exit 0
|
||||
|
||||
@@ -23,7 +23,7 @@ function update_fleet_urls() {
|
||||
}
|
||||
|
||||
# Get current list of Fleet Server URLs
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/fleet_server_hosts/grid-default')
|
||||
RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/fleet_server_hosts/grid-default' --retry 3 --retry-delay 30 --fail 2>/dev/null)
|
||||
|
||||
# Check to make sure that the server responded with good data - else, bail from script
|
||||
CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON")
|
||||
|
||||
@@ -34,6 +34,11 @@ if [[ "$RETURN_CODE" != "0" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/pki/elasticfleet-kafka.crt || ! -f /etc/pki/elasticfleet-kafka.key ]]; then
|
||||
echo -e "\nKafka certificates not found, can't setup Elastic Fleet output policy for Kafka...\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KAFKACRT=$(openssl x509 -in /etc/pki/elasticfleet-kafka.crt)
|
||||
KAFKAKEY=$(openssl rsa -in /etc/pki/elasticfleet-kafka.key)
|
||||
KAFKACA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
||||
@@ -47,7 +52,7 @@ if ! kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l
|
||||
--arg KAFKACA "$KAFKACA" \
|
||||
--arg MANAGER_IP "{{ GLOBALS.manager_ip }}:9092" \
|
||||
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
||||
'{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||
'{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||
)
|
||||
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
||||
echo -e "\nFailed to setup Elastic Fleet output policy for Kafka...\n"
|
||||
@@ -67,7 +72,7 @@ elif kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l
|
||||
--arg ENABLED_DISABLED "$ENABLED_DISABLED"\
|
||||
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
||||
--argjson HOSTS "$HOSTS" \
|
||||
'{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||
'{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||
)
|
||||
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
||||
echo -e "\nFailed to force update to Elastic Fleet output policy for Kafka...\n"
|
||||
|
||||
@@ -26,14 +26,14 @@ catrustscript:
|
||||
GLOBALS: {{ GLOBALS }}
|
||||
{% endif %}
|
||||
|
||||
cacertz:
|
||||
elasticsearch_cacerts:
|
||||
file.managed:
|
||||
- name: /opt/so/conf/ca/cacerts
|
||||
- source: salt://elasticsearch/cacerts
|
||||
- user: 939
|
||||
- group: 939
|
||||
|
||||
capemz:
|
||||
elasticsearch_capems:
|
||||
file.managed:
|
||||
- name: /opt/so/conf/ca/tls-ca-bundle.pem
|
||||
- source: salt://elasticsearch/tls-ca-bundle.pem
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
|
||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||
{% if sls.split('.')[0] in allowed_states %}
|
||||
|
||||
include:
|
||||
- ssl
|
||||
- elasticsearch.ca
|
||||
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
{% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
elasticsearch:
|
||||
enabled: false
|
||||
version: 8.18.8
|
||||
version: 9.0.8
|
||||
index_clean: true
|
||||
config:
|
||||
action:
|
||||
destructive_requires_name: true
|
||||
cluster:
|
||||
logsdb:
|
||||
enabled: false
|
||||
routing:
|
||||
allocation:
|
||||
disk:
|
||||
@@ -299,6 +301,19 @@ elasticsearch:
|
||||
hot:
|
||||
actions: {}
|
||||
min_age: 0ms
|
||||
sos-backup:
|
||||
index_sorting: false
|
||||
index_template:
|
||||
composed_of: []
|
||||
ignore_missing_component_templates: []
|
||||
index_patterns:
|
||||
- sos-backup-*
|
||||
priority: 501
|
||||
template:
|
||||
settings:
|
||||
index:
|
||||
number_of_replicas: 0
|
||||
number_of_shards: 1
|
||||
so-assistant-chat:
|
||||
index_sorting: false
|
||||
index_template:
|
||||
@@ -678,7 +693,6 @@ elasticsearch:
|
||||
match_mapping_type: string
|
||||
settings:
|
||||
index:
|
||||
final_pipeline: .fleet_final_pipeline-1
|
||||
lifecycle:
|
||||
name: so-import-logs
|
||||
mapping:
|
||||
@@ -844,53 +858,11 @@ elasticsearch:
|
||||
composed_of:
|
||||
- agent-mappings
|
||||
- dtc-agent-mappings
|
||||
- base-mappings
|
||||
- dtc-base-mappings
|
||||
- client-mappings
|
||||
- dtc-client-mappings
|
||||
- container-mappings
|
||||
- destination-mappings
|
||||
- dtc-destination-mappings
|
||||
- pb-override-destination-mappings
|
||||
- dll-mappings
|
||||
- dns-mappings
|
||||
- dtc-dns-mappings
|
||||
- ecs-mappings
|
||||
- dtc-ecs-mappings
|
||||
- error-mappings
|
||||
- event-mappings
|
||||
- dtc-event-mappings
|
||||
- file-mappings
|
||||
- dtc-file-mappings
|
||||
- group-mappings
|
||||
- host-mappings
|
||||
- dtc-host-mappings
|
||||
- http-mappings
|
||||
- dtc-http-mappings
|
||||
- log-mappings
|
||||
- metadata-mappings
|
||||
- network-mappings
|
||||
- dtc-network-mappings
|
||||
- observer-mappings
|
||||
- dtc-observer-mappings
|
||||
- organization-mappings
|
||||
- package-mappings
|
||||
- process-mappings
|
||||
- dtc-process-mappings
|
||||
- related-mappings
|
||||
- rule-mappings
|
||||
- dtc-rule-mappings
|
||||
- server-mappings
|
||||
- service-mappings
|
||||
- dtc-service-mappings
|
||||
- source-mappings
|
||||
- dtc-source-mappings
|
||||
- pb-override-source-mappings
|
||||
- threat-mappings
|
||||
- tls-mappings
|
||||
- url-mappings
|
||||
- user_agent-mappings
|
||||
- dtc-user_agent-mappings
|
||||
- common-settings
|
||||
- common-dynamic-mappings
|
||||
data_stream:
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
{% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS %}
|
||||
|
||||
include:
|
||||
- ca
|
||||
- elasticsearch.ca
|
||||
- elasticsearch.ssl
|
||||
- elasticsearch.config
|
||||
- elasticsearch.sostatus
|
||||
|
||||
@@ -61,11 +64,7 @@ so-elasticsearch:
|
||||
- /nsm/elasticsearch:/usr/share/elasticsearch/data:rw
|
||||
- /opt/so/log/elasticsearch:/var/log/elasticsearch:rw
|
||||
- /opt/so/conf/ca/cacerts:/usr/share/elasticsearch/jdk/lib/security/cacerts:ro
|
||||
{% if GLOBALS.is_manager %}
|
||||
- /etc/pki/ca.crt:/usr/share/elasticsearch/config/ca.crt:ro
|
||||
{% else %}
|
||||
- /etc/pki/tls/certs/intca.crt:/usr/share/elasticsearch/config/ca.crt:ro
|
||||
{% endif %}
|
||||
- /etc/pki/elasticsearch.crt:/usr/share/elasticsearch/config/elasticsearch.crt:ro
|
||||
- /etc/pki/elasticsearch.key:/usr/share/elasticsearch/config/elasticsearch.key:ro
|
||||
- /etc/pki/elasticsearch.p12:/usr/share/elasticsearch/config/elasticsearch.p12:ro
|
||||
@@ -82,22 +81,21 @@ so-elasticsearch:
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- watch:
|
||||
- file: cacertz
|
||||
- file: trusttheca
|
||||
- x509: elasticsearch_crt
|
||||
- x509: elasticsearch_key
|
||||
- file: elasticsearch_cacerts
|
||||
- file: esyml
|
||||
- require:
|
||||
- file: trusttheca
|
||||
- x509: elasticsearch_crt
|
||||
- x509: elasticsearch_key
|
||||
- file: elasticsearch_cacerts
|
||||
- file: esyml
|
||||
- file: eslog4jfile
|
||||
- file: nsmesdir
|
||||
- file: eslogdir
|
||||
- file: cacertz
|
||||
- x509: /etc/pki/elasticsearch.crt
|
||||
- x509: /etc/pki/elasticsearch.key
|
||||
- file: elasticp12perms
|
||||
{% if GLOBALS.is_manager %}
|
||||
- x509: pki_public_ca_crt
|
||||
{% else %}
|
||||
- x509: trusttheca
|
||||
{% endif %}
|
||||
- cmd: auth_users_roles_inode
|
||||
- cmd: auth_users_inode
|
||||
|
||||
|
||||
@@ -1,31 +1,212 @@
|
||||
{
|
||||
"version": 3,
|
||||
"_meta": {
|
||||
"managed_by": "securityonion",
|
||||
"managed": true
|
||||
},
|
||||
"description": "Custom pipeline for processing all incoming Fleet Agent documents. \n",
|
||||
"processors": [
|
||||
{ "set": { "ignore_failure": true, "field": "event.module", "value": "elastic_agent" } },
|
||||
{ "split": { "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", "field": "event.dataset", "separator": "\\.", "target_field": "module_temp" } },
|
||||
{ "split": { "if": "ctx.data_stream?.dataset != null && ctx.data_stream?.dataset.contains('.')", "field":"data_stream.dataset", "separator":"\\.", "target_field":"datastream_dataset_temp", "ignore_missing":true } },
|
||||
{ "set": { "if": "ctx.module_temp != null", "override": true, "field": "event.module", "value": "{{module_temp.0}}" } },
|
||||
{ "set": { "if": "ctx.datastream_dataset_temp != null && ctx.datastream_dataset_temp[0] == 'network_traffic'", "field":"event.module", "value":"{{ datastream_dataset_temp.0 }}", "ignore_failure":true, "ignore_empty_value":true, "description":"Fix EA network packet capture" } },
|
||||
{ "gsub": { "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", "field": "event.dataset", "pattern": "^[^.]*.", "replacement": "", "target_field": "dataset_tag_temp" } },
|
||||
{ "append": { "if": "ctx.dataset_tag_temp != null", "field": "tags", "value": "{{dataset_tag_temp}}", "allow_duplicates": false } },
|
||||
{ "set": { "if": "ctx.network?.direction == 'egress'", "override": true, "field": "network.initiated", "value": "true" } },
|
||||
{ "set": { "if": "ctx.network?.direction == 'ingress'", "override": true, "field": "network.initiated", "value": "false" } },
|
||||
{ "set": { "if": "ctx.network?.type == 'ipv4'", "override": true, "field": "destination.ipv6", "value": "false" } },
|
||||
{ "set": { "if": "ctx.network?.type == 'ipv6'", "override": true, "field": "destination.ipv6", "value": "true" } },
|
||||
{ "set": { "if": "ctx.tags != null && ctx.tags.contains('import')", "override": true, "field": "data_stream.dataset", "value": "import" } },
|
||||
{ "set": { "if": "ctx.tags != null && ctx.tags.contains('import')", "override": true, "field": "data_stream.namespace", "value": "so" } },
|
||||
{ "community_id":{ "if": "ctx.event?.dataset == 'endpoint.events.network'", "ignore_failure":true } },
|
||||
{ "set": { "if": "ctx.event?.module == 'fim'", "override": true, "field": "event.module", "value": "file_integrity" } },
|
||||
{ "rename": { "if": "ctx.winlog?.provider_name == 'Microsoft-Windows-Windows Defender'", "ignore_missing": true, "field": "winlog.event_data.Threat Name", "target_field": "winlog.event_data.threat_name" } },
|
||||
{ "set": { "if": "ctx?.metadata?.kafka != null" , "field": "kafka.id", "value": "{{metadata.kafka.partition}}{{metadata.kafka.offset}}{{metadata.kafka.timestamp}}", "ignore_failure": true } },
|
||||
{ "set": { "if": "ctx.event?.dataset != null && ctx.event?.dataset == 'elasticsearch.server'", "field": "event.module", "value":"elasticsearch" }},
|
||||
{"append": {"field":"related.ip","value":["{{source.ip}}","{{destination.ip}}"],"allow_duplicates":false,"if":"ctx?.event?.dataset == 'endpoint.events.network' && ctx?.source?.ip != null","ignore_failure":true}},
|
||||
{"foreach": {"field":"host.ip","processor":{"append":{"field":"related.ip","value":"{{_ingest._value}}","allow_duplicates":false}},"if":"ctx?.event?.module == 'endpoint' && ctx?.host?.ip != null","ignore_missing":true, "description":"Extract IPs from Elastic Agent events (host.ip) and adds them to related.ip"}},
|
||||
{ "remove": { "field": [ "message2", "type", "fields", "category", "module", "dataset", "event.dataset_temp", "dataset_tag_temp", "module_temp", "datastream_dataset_temp" ], "ignore_missing": true, "ignore_failure": true } }
|
||||
]
|
||||
}
|
||||
"version": 3,
|
||||
"_meta": {
|
||||
"managed_by": "securityonion",
|
||||
"managed": true
|
||||
},
|
||||
"description": "Custom pipeline for processing all incoming Fleet Agent documents. \n",
|
||||
"processors": [
|
||||
{
|
||||
"set": {
|
||||
"ignore_failure": true,
|
||||
"field": "event.module",
|
||||
"value": "elastic_agent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"split": {
|
||||
"if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')",
|
||||
"field": "event.dataset",
|
||||
"separator": "\\.",
|
||||
"target_field": "module_temp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"split": {
|
||||
"if": "ctx.data_stream?.dataset != null && ctx.data_stream?.dataset.contains('.')",
|
||||
"field": "data_stream.dataset",
|
||||
"separator": "\\.",
|
||||
"target_field": "datastream_dataset_temp",
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.module_temp != null",
|
||||
"override": true,
|
||||
"field": "event.module",
|
||||
"value": "{{module_temp.0}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.datastream_dataset_temp != null && ctx.datastream_dataset_temp[0] == 'network_traffic'",
|
||||
"field": "event.module",
|
||||
"value": "{{ datastream_dataset_temp.0 }}",
|
||||
"ignore_failure": true,
|
||||
"ignore_empty_value": true,
|
||||
"description": "Fix EA network packet capture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"gsub": {
|
||||
"if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')",
|
||||
"field": "event.dataset",
|
||||
"pattern": "^[^.]*.",
|
||||
"replacement": "",
|
||||
"target_field": "dataset_tag_temp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"append": {
|
||||
"if": "ctx.dataset_tag_temp != null",
|
||||
"field": "tags",
|
||||
"value": "{{dataset_tag_temp}}",
|
||||
"allow_duplicates": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.network?.direction == 'egress'",
|
||||
"override": true,
|
||||
"field": "network.initiated",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.network?.direction == 'ingress'",
|
||||
"override": true,
|
||||
"field": "network.initiated",
|
||||
"value": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.network?.type == 'ipv4'",
|
||||
"override": true,
|
||||
"field": "destination.ipv6",
|
||||
"value": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.network?.type == 'ipv6'",
|
||||
"override": true,
|
||||
"field": "destination.ipv6",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.tags != null && ctx.tags.contains('import')",
|
||||
"override": true,
|
||||
"field": "data_stream.dataset",
|
||||
"value": "import"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.tags != null && ctx.tags.contains('import')",
|
||||
"override": true,
|
||||
"field": "data_stream.namespace",
|
||||
"value": "so"
|
||||
}
|
||||
},
|
||||
{
|
||||
"community_id": {
|
||||
"if": "ctx.event?.dataset == 'endpoint.events.network'",
|
||||
"ignore_failure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.event?.module == 'fim'",
|
||||
"override": true,
|
||||
"field": "event.module",
|
||||
"value": "file_integrity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"if": "ctx.winlog?.provider_name == 'Microsoft-Windows-Windows Defender'",
|
||||
"ignore_missing": true,
|
||||
"field": "winlog.event_data.Threat Name",
|
||||
"target_field": "winlog.event_data.threat_name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx?.metadata?.kafka != null",
|
||||
"field": "kafka.id",
|
||||
"value": "{{metadata.kafka.partition}}{{metadata.kafka.offset}}{{metadata.kafka.timestamp}}",
|
||||
"ignore_failure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"if": "ctx.event?.dataset != null && ctx.event?.dataset == 'elasticsearch.server'",
|
||||
"field": "event.module",
|
||||
"value": "elasticsearch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"append": {
|
||||
"field": "related.ip",
|
||||
"value": [
|
||||
"{{source.ip}}",
|
||||
"{{destination.ip}}"
|
||||
],
|
||||
"allow_duplicates": false,
|
||||
"if": "ctx?.event?.dataset == 'endpoint.events.network' && ctx?.source?.ip != null",
|
||||
"ignore_failure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"foreach": {
|
||||
"field": "host.ip",
|
||||
"processor": {
|
||||
"append": {
|
||||
"field": "related.ip",
|
||||
"value": "{{_ingest._value}}",
|
||||
"allow_duplicates": false
|
||||
}
|
||||
},
|
||||
"if": "ctx?.event?.module == 'endpoint' && ctx?.host?.ip != null",
|
||||
"ignore_missing": true,
|
||||
"description": "Extract IPs from Elastic Agent events (host.ip) and adds them to related.ip"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pipeline": {
|
||||
"name": ".fleet_final_pipeline-1",
|
||||
"ignore_missing_pipeline": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"remove": {
|
||||
"field": "event.agent_id_status",
|
||||
"ignore_missing": true,
|
||||
"if": "ctx?.event?.agent_id_status == 'auth_metadata_missing'"
|
||||
}
|
||||
},
|
||||
{
|
||||
"remove": {
|
||||
"field": [
|
||||
"message2",
|
||||
"type",
|
||||
"fields",
|
||||
"category",
|
||||
"module",
|
||||
"dataset",
|
||||
"event.dataset_temp",
|
||||
"dataset_tag_temp",
|
||||
"module_temp",
|
||||
"datastream_dataset_temp"
|
||||
],
|
||||
"ignore_missing": true,
|
||||
"ignore_failure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,90 @@
|
||||
{
|
||||
"description" : "kratos",
|
||||
"processors" : [
|
||||
{"set":{"field":"audience","value":"access","override":false,"ignore_failure":true}},
|
||||
{"set":{"field":"event.dataset","ignore_empty_value":true,"ignore_failure":true,"value":"kratos.{{{audience}}}","media_type":"text/plain"}},
|
||||
{"set":{"field":"event.action","ignore_failure":true,"copy_from":"msg" }},
|
||||
{ "pipeline": { "name": "common" } }
|
||||
]
|
||||
"description": "kratos",
|
||||
"processors": [
|
||||
{
|
||||
"set": {
|
||||
"field": "audience",
|
||||
"value": "access",
|
||||
"override": false,
|
||||
"ignore_failure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"field": "event.dataset",
|
||||
"ignore_empty_value": true,
|
||||
"ignore_failure": true,
|
||||
"value": "kratos.{{{audience}}}",
|
||||
"media_type": "text/plain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"set": {
|
||||
"field": "event.action",
|
||||
"ignore_failure": true,
|
||||
"copy_from": "msg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http_request",
|
||||
"target_field": "http.request",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http_response",
|
||||
"target_field": "http.response",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http.request.path",
|
||||
"target_field": "http.uri",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http.request.method",
|
||||
"target_field": "http.method",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http.request.method",
|
||||
"target_field": "http.method",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http.request.query",
|
||||
"target_field": "http.query",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"rename": {
|
||||
"field": "http.request.headers.user-agent",
|
||||
"target_field": "http.useragent",
|
||||
"ignore_failure": true,
|
||||
"ignore_missing": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"pipeline": {
|
||||
"name": "common"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -27,6 +27,13 @@ elasticsearch:
|
||||
readonly: True
|
||||
global: True
|
||||
helpLink: elasticsearch.html
|
||||
logsdb:
|
||||
enabled:
|
||||
description: Enables or disables the Elasticsearch logsdb index mode. When enabled, most logs-* datastreams will convert to logsdb from standard after rolling over.
|
||||
forcedType: bool
|
||||
global: True
|
||||
advanced: True
|
||||
helpLink: elasticsearch.html
|
||||
routing:
|
||||
allocation:
|
||||
disk:
|
||||
|
||||
66
salt/elasticsearch/ssl.sls
Normal file
66
salt/elasticsearch/ssl.sls
Normal file
@@ -0,0 +1,66 @@
|
||||
# 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 %}
|
||||
|
||||
# Create a cert for elasticsearch
|
||||
elasticsearch_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticsearch.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticsearch.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/elasticsearch.crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
elasticsearch_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticsearch.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: registry
|
||||
- private_key: /etc/pki/elasticsearch.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/elasticsearch.key -in /etc/pki/elasticsearch.crt -export -out /etc/pki/elasticsearch.p12 -nodes -passout pass:"
|
||||
- onchanges:
|
||||
- x509: /etc/pki/elasticsearch.key
|
||||
|
||||
elastickeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticsearch.key
|
||||
- mode: 640
|
||||
- group: 930
|
||||
|
||||
elasticp12perms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticsearch.p12
|
||||
- mode: 640
|
||||
- group: 930
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -2,7 +2,7 @@
|
||||
"template": {
|
||||
"settings": {
|
||||
"index": {
|
||||
"final_pipeline": ".fleet_final_pipeline-1"
|
||||
"final_pipeline": "global@custom"
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
|
||||
@@ -14,8 +14,9 @@ set -e
|
||||
# Check to see if we have extracted the ca cert.
|
||||
if [ ! -f /opt/so/saltstack/local/salt/elasticsearch/cacerts ]; then
|
||||
docker run -v /etc/pki/ca.crt:/etc/ssl/ca.crt --name so-elasticsearchca --user root --entrypoint jdk/bin/keytool {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:$ELASTIC_AGENT_TARBALL_VERSION -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -alias SOSCA -import -file /etc/ssl/ca.crt -storepass changeit -noprompt
|
||||
docker cp so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts
|
||||
docker cp so-elasticsearchca:/etc/ssl/certs/ca-certificates.crt /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||
# Make sure symbolic links are followed when copying from container
|
||||
docker cp -L so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts
|
||||
docker cp -L so-elasticsearchca:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||
docker rm so-elasticsearchca
|
||||
echo "" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||
echo "sosca" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||
|
||||
@@ -121,7 +121,7 @@ if [ ! -f $STATE_FILE_SUCCESS ]; then
|
||||
echo "Loading Security Onion index templates..."
|
||||
shopt -s extglob
|
||||
{% if GLOBALS.role == 'so-heavynode' %}
|
||||
pattern="!(*1password*|*aws*|*azure*|*cloudflare*|*elastic_agent*|*fim*|*github*|*google*|*osquery*|*system*|*windows*)"
|
||||
pattern="!(*1password*|*aws*|*azure*|*cloudflare*|*elastic_agent*|*fim*|*github*|*google*|*osquery*|*system*|*windows*|*endpoint*|*elasticsearch*|*generic*|*fleet_server*|*soc*)"
|
||||
{% else %}
|
||||
pattern="*"
|
||||
{% endif %}
|
||||
|
||||
@@ -32,7 +32,7 @@ global:
|
||||
readonly: True
|
||||
advanced: True
|
||||
url_base:
|
||||
description: Used for handling of authentication cookies.
|
||||
description: The base URL for the Security Onion Console. Must be accessible by all nodes in the grid, as well as all analysts. Also used for handling of authentication cookies. Can be an IP address or a hostname/FQDN. Do not include protocol (http/https) or port number.
|
||||
global: True
|
||||
airgap:
|
||||
description: Airgapped systems do not have network connectivity to the internet. This setting represents how this grid was configured during initial setup. While it is technically possible to manually switch systems between airgap and non-airgap, there are some nuances and additional steps involved. For that reason this setting is marked read-only. Contact your support representative for guidance if there is a need to change this setting.
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
include:
|
||||
- salt.minion
|
||||
- ssl
|
||||
|
||||
# Influx DB
|
||||
influxconfdir:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
{% set TOKEN = salt['pillar.get']('influxdb:token') %}
|
||||
|
||||
include:
|
||||
- influxdb.ssl
|
||||
- influxdb.config
|
||||
- influxdb.sostatus
|
||||
|
||||
@@ -59,6 +60,8 @@ so-influxdb:
|
||||
{% endif %}
|
||||
- watch:
|
||||
- file: influxdbconf
|
||||
- x509: influxdb_key
|
||||
- x509: influxdb_crt
|
||||
- require:
|
||||
- file: influxdbconf
|
||||
- x509: influxdb_key
|
||||
|
||||
55
salt/influxdb/ssl.sls
Normal file
55
salt/influxdb/ssl.sls
Normal file
@@ -0,0 +1,55 @@
|
||||
# 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 %}
|
||||
|
||||
influxdb_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/influxdb.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/influxdb.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/influxdb.crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
# Create a cert for the talking to influxdb
|
||||
influxdb_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/influxdb.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: influxdb
|
||||
- private_key: /etc/pki/influxdb.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
influxkeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/influxdb.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -68,6 +68,8 @@ so-kafka:
|
||||
- file: kafka_server_jaas_properties
|
||||
{% endif %}
|
||||
- file: kafkacertz
|
||||
- x509: kafka_crt
|
||||
- file: kafka_pkcs12_perms
|
||||
- require:
|
||||
- file: kafkacertz
|
||||
|
||||
@@ -95,4 +97,4 @@ include:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -6,22 +6,13 @@
|
||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||
{% if sls.split('.')[0] in allowed_states or sls in allowed_states %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
{% from 'ca/map.jinja' import CA %}
|
||||
{% set kafka_password = salt['pillar.get']('kafka:config:password') %}
|
||||
|
||||
include:
|
||||
- ca.dirs
|
||||
{% set global_ca_server = [] %}
|
||||
{% set x509dict = salt['mine.get'](GLOBALS.manager | lower~'*', 'x509.get_pem_entries') %}
|
||||
{% for host in x509dict %}
|
||||
{% if 'manager' in host.split('_')|last or host.split('_')|last == 'standalone' %}
|
||||
{% do global_ca_server.append(host) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set ca_server = global_ca_server[0] %}
|
||||
- ca
|
||||
|
||||
{% if GLOBALS.pipeline == "KAFKA" %}
|
||||
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone'] %}
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone'] %}
|
||||
kafka_client_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/kafka-client.key
|
||||
@@ -39,12 +30,12 @@ kafka_client_key:
|
||||
kafka_client_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/kafka-client.crt
|
||||
- ca_server: {{ ca_server }}
|
||||
- ca_server: {{ CA.server }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- signing_policy: kafka
|
||||
- private_key: /etc/pki/kafka-client.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- days_remaining: 0
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
@@ -67,9 +58,9 @@ kafka_client_crt_perms:
|
||||
- mode: 640
|
||||
- user: 960
|
||||
- group: 939
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managersearch','so-receiver', 'so-standalone'] %}
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managersearch','so-receiver', 'so-standalone'] %}
|
||||
kafka_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/kafka.key
|
||||
@@ -87,12 +78,12 @@ kafka_key:
|
||||
kafka_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/kafka.crt
|
||||
- ca_server: {{ ca_server }}
|
||||
- ca_server: {{ CA.server }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- signing_policy: kafka
|
||||
- private_key: /etc/pki/kafka.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- days_remaining: 0
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
@@ -103,6 +94,7 @@ kafka_crt:
|
||||
- name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/kafka.key -in /etc/pki/kafka.crt -export -out /etc/pki/kafka.p12 -nodes -passout pass:{{ kafka_password }}"
|
||||
- onchanges:
|
||||
- x509: /etc/pki/kafka.key
|
||||
|
||||
kafka_key_perms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
@@ -126,11 +118,11 @@ kafka_pkcs12_perms:
|
||||
- mode: 640
|
||||
- user: 960
|
||||
- group: 939
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# Standalone needs kafka-logstash for automated testing. Searchnode/manager search need it for logstash to consume from Kafka.
|
||||
# Manager will have cert, but be unused until a pipeline is created and logstash enabled.
|
||||
{% if GLOBALS.role in ['so-standalone', 'so-managersearch', 'so-searchnode', 'so-manager'] %}
|
||||
{% if GLOBALS.role in ['so-standalone', 'so-managersearch', 'so-searchnode', 'so-manager'] %}
|
||||
kafka_logstash_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/kafka-logstash.key
|
||||
@@ -148,12 +140,12 @@ kafka_logstash_key:
|
||||
kafka_logstash_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/kafka-logstash.crt
|
||||
- ca_server: {{ ca_server }}
|
||||
- ca_server: {{ CA.server }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- signing_policy: kafka
|
||||
- private_key: /etc/pki/kafka-logstash.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- days_remaining: 0
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
@@ -189,7 +181,6 @@ kafka_logstash_pkcs12_perms:
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
@@ -198,4 +189,4 @@ kafka_logstash_pkcs12_perms:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -25,11 +25,10 @@ kibana:
|
||||
discardCorruptObjects: "8.18.8"
|
||||
telemetry:
|
||||
enabled: False
|
||||
security:
|
||||
showInsecureClusterWarning: False
|
||||
xpack:
|
||||
security:
|
||||
secureCookies: true
|
||||
showInsecureClusterWarning: false
|
||||
reporting:
|
||||
kibanaServer:
|
||||
hostname: localhost
|
||||
|
||||
@@ -75,6 +75,7 @@ kratosconfig:
|
||||
- group: 928
|
||||
- mode: 600
|
||||
- template: jinja
|
||||
- show_changes: False
|
||||
- defaults:
|
||||
KRATOSMERGED: {{ KRATOSMERGED }}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ kratos:
|
||||
ui_url: https://URL_BASE/
|
||||
login:
|
||||
ui_url: https://URL_BASE/login/
|
||||
lifespan: 60m
|
||||
error:
|
||||
ui_url: https://URL_BASE/login/
|
||||
registration:
|
||||
|
||||
@@ -182,6 +182,10 @@ kratos:
|
||||
global: True
|
||||
advanced: True
|
||||
helpLink: kratos.html
|
||||
lifespan:
|
||||
description: Defines the duration that a login form will remain valid.
|
||||
global: True
|
||||
helpLink: kratos.html
|
||||
error:
|
||||
ui_url:
|
||||
description: User accessible URL containing the Security Onion login page. Leave as default to ensure proper operation.
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
{% from 'logstash/map.jinja' import LOGSTASH_MERGED %}
|
||||
{% set ASSIGNED_PIPELINES = LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %}
|
||||
|
||||
{% if GLOBALS.role not in ['so-receiver','so-fleet'] %}
|
||||
include:
|
||||
- ssl
|
||||
{% if GLOBALS.role not in ['so-receiver','so-fleet'] %}
|
||||
- elasticsearch
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# Create the logstash group
|
||||
logstashgroup:
|
||||
|
||||
@@ -63,7 +63,7 @@ logstash:
|
||||
settings:
|
||||
lsheap: 500m
|
||||
config:
|
||||
http_x_host: 0.0.0.0
|
||||
api_x_http_x_host: 0.0.0.0
|
||||
path_x_logs: /var/log/logstash
|
||||
pipeline_x_workers: 1
|
||||
pipeline_x_batch_x_size: 125
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
{% set lsheap = LOGSTASH_MERGED.settings.lsheap %}
|
||||
|
||||
include:
|
||||
- ca
|
||||
{% if GLOBALS.role not in ['so-receiver','so-fleet'] %}
|
||||
- elasticsearch.ca
|
||||
{% endif %}
|
||||
@@ -20,9 +21,9 @@ include:
|
||||
- kafka.ca
|
||||
- kafka.ssl
|
||||
{% endif %}
|
||||
- logstash.ssl
|
||||
- logstash.config
|
||||
- logstash.sostatus
|
||||
- ssl
|
||||
|
||||
so-logstash:
|
||||
docker_container.running:
|
||||
@@ -65,22 +66,18 @@ so-logstash:
|
||||
- /opt/so/log/logstash:/var/log/logstash:rw
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
- /opt/so/conf/logstash/etc/certs:/usr/share/logstash/certs:ro
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %}
|
||||
- /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro
|
||||
- /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro
|
||||
{% endif %}
|
||||
- /etc/pki/tls/certs/intca.crt:/usr/share/filebeat/ca.crt:ro
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %}
|
||||
- /etc/pki/elasticfleet-logstash.crt:/usr/share/logstash/elasticfleet-logstash.crt:ro
|
||||
- /etc/pki/elasticfleet-logstash.key:/usr/share/logstash/elasticfleet-logstash.key:ro
|
||||
- /etc/pki/elasticfleet-lumberjack.crt:/usr/share/logstash/elasticfleet-lumberjack.crt:ro
|
||||
- /etc/pki/elasticfleet-lumberjack.key:/usr/share/logstash/elasticfleet-lumberjack.key:ro
|
||||
{% if GLOBALS.role != 'so-fleet' %}
|
||||
- /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro
|
||||
- /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %}
|
||||
- /etc/pki/ca.crt:/usr/share/filebeat/ca.crt:ro
|
||||
{% else %}
|
||||
- /etc/pki/tls/certs/intca.crt:/usr/share/filebeat/ca.crt:ro
|
||||
{% endif %}
|
||||
{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode' ] %}
|
||||
{% if GLOBALS.role not in ['so-receiver','so-fleet'] %}
|
||||
- /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro
|
||||
- /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro
|
||||
{% endif %}
|
||||
@@ -100,11 +97,22 @@ so-logstash:
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- watch:
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-receiver'] %}
|
||||
- x509: etc_elasticfleet_logstash_key
|
||||
- x509: etc_elasticfleet_logstash_crt
|
||||
{% endif %}
|
||||
- file: lsetcsync
|
||||
- file: trusttheca
|
||||
{% if GLOBALS.is_manager %}
|
||||
- file: elasticsearch_cacerts
|
||||
- file: elasticsearch_capems
|
||||
{% endif %}
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %}
|
||||
- x509: etc_elasticfleet_logstash_crt
|
||||
- x509: etc_elasticfleet_logstash_key
|
||||
- x509: etc_elasticfleetlumberjack_crt
|
||||
- x509: etc_elasticfleetlumberjack_key
|
||||
{% if GLOBALS.role != 'so-fleet' %}
|
||||
- x509: etc_filebeat_crt
|
||||
- file: logstash_filebeat_p8
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% for assigned_pipeline in LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %}
|
||||
- file: ls_pipeline_{{assigned_pipeline}}
|
||||
{% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %}
|
||||
@@ -115,17 +123,20 @@ so-logstash:
|
||||
- file: kafkacertz
|
||||
{% endif %}
|
||||
- require:
|
||||
{% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %}
|
||||
- file: trusttheca
|
||||
{% if GLOBALS.is_manager %}
|
||||
- file: elasticsearch_cacerts
|
||||
- file: elasticsearch_capems
|
||||
{% endif %}
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %}
|
||||
- x509: etc_elasticfleet_logstash_crt
|
||||
- x509: etc_elasticfleet_logstash_key
|
||||
- x509: etc_elasticfleetlumberjack_crt
|
||||
- x509: etc_elasticfleetlumberjack_key
|
||||
{% if GLOBALS.role != 'so-fleet' %}
|
||||
- x509: etc_filebeat_crt
|
||||
{% endif %}
|
||||
{% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %}
|
||||
- x509: pki_public_ca_crt
|
||||
{% else %}
|
||||
- x509: trusttheca
|
||||
{% endif %}
|
||||
{% if grains.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %}
|
||||
- file: cacertz
|
||||
- file: capemz
|
||||
- file: logstash_filebeat_p8
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %}
|
||||
- file: kafkacertz
|
||||
|
||||
@@ -5,10 +5,10 @@ input {
|
||||
codec => es_bulk
|
||||
request_headers_target_field => client_headers
|
||||
remote_host_target_field => client_host
|
||||
ssl => true
|
||||
ssl_enabled => true
|
||||
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
||||
ssl_certificate => "/usr/share/logstash/filebeat.crt"
|
||||
ssl_key => "/usr/share/logstash/filebeat.key"
|
||||
ssl_verify_mode => "peer"
|
||||
ssl_client_authentication => "required"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ input {
|
||||
elastic_agent {
|
||||
port => 5055
|
||||
tags => [ "elastic-agent", "input-{{ GLOBALS.hostname }}" ]
|
||||
ssl => true
|
||||
ssl_enabled => true
|
||||
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
||||
ssl_certificate => "/usr/share/logstash/elasticfleet-logstash.crt"
|
||||
ssl_key => "/usr/share/logstash/elasticfleet-logstash.key"
|
||||
ssl_verify_mode => "force_peer"
|
||||
ssl_client_authentication => "required"
|
||||
ecs_compatibility => v8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ input {
|
||||
elastic_agent {
|
||||
port => 5056
|
||||
tags => [ "elastic-agent", "fleet-lumberjack-input" ]
|
||||
ssl => true
|
||||
ssl_enabled => true
|
||||
ssl_certificate => "/usr/share/logstash/elasticfleet-lumberjack.crt"
|
||||
ssl_key => "/usr/share/logstash/elasticfleet-lumberjack.key"
|
||||
ecs_compatibility => v8
|
||||
|
||||
@@ -8,8 +8,8 @@ output {
|
||||
document_id => "%{[metadata][_id]}"
|
||||
index => "so-ip-mappings"
|
||||
silence_errors_in_log => ["version_conflict_engine_exception"]
|
||||
ssl => true
|
||||
ssl_certificate_verification => false
|
||||
ssl_enabled => true
|
||||
ssl_verification_mode => "none"
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -25,8 +25,8 @@ output {
|
||||
document_id => "%{[metadata][_id]}"
|
||||
pipeline => "%{[metadata][pipeline]}"
|
||||
silence_errors_in_log => ["version_conflict_engine_exception"]
|
||||
ssl => true
|
||||
ssl_certificate_verification => false
|
||||
ssl_enabled => true
|
||||
ssl_verification_mode => "none"
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -37,8 +37,8 @@ output {
|
||||
user => "{{ ES_USER }}"
|
||||
password => "{{ ES_PASS }}"
|
||||
pipeline => "%{[metadata][pipeline]}"
|
||||
ssl => true
|
||||
ssl_certificate_verification => false
|
||||
ssl_enabled => true
|
||||
ssl_verification_mode => "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,8 @@ output {
|
||||
data_stream => true
|
||||
user => "{{ ES_USER }}"
|
||||
password => "{{ ES_PASS }}"
|
||||
ssl => true
|
||||
ssl_certificate_verification => false
|
||||
ssl_enabled => true
|
||||
ssl_verification_mode=> "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ output {
|
||||
user => "{{ ES_USER }}"
|
||||
password => "{{ ES_PASS }}"
|
||||
index => "endgame-%{+YYYY.MM.dd}"
|
||||
ssl => true
|
||||
ssl_certificate_verification => false
|
||||
ssl_enabled => true
|
||||
ssl_verification_mode => "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ logstash:
|
||||
helpLink: logstash.html
|
||||
global: False
|
||||
config:
|
||||
http_x_host:
|
||||
api_x_http_x_host:
|
||||
description: Host interface to listen to connections.
|
||||
helpLink: logstash.html
|
||||
readonly: True
|
||||
|
||||
287
salt/logstash/ssl.sls
Normal file
287
salt/logstash/ssl.sls
Normal file
@@ -0,0 +1,287 @@
|
||||
# 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 or sls.split('.')[0] in allowed_states %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||
{% from 'ca/map.jinja' import CA %}
|
||||
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %}
|
||||
|
||||
{% if grains['role'] not in [ 'so-heavynode'] %}
|
||||
# Start -- Elastic Fleet Logstash Input Cert
|
||||
etc_elasticfleet_logstash_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticfleet-logstash.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticfleet-logstash.key') -%}
|
||||
- prereq:
|
||||
- x509: etc_elasticfleet_logstash_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
etc_elasticfleet_logstash_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticfleet-logstash.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: elasticfleet
|
||||
- private_key: /etc/pki/elasticfleet-logstash.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-logstash.key -topk8 -out /etc/pki/elasticfleet-logstash.p8 -nocrypt"
|
||||
- onchanges:
|
||||
- x509: etc_elasticfleet_logstash_key
|
||||
|
||||
eflogstashperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-logstash.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetlogstashcrt:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-logstash.crt
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
chownelasticfleetlogstashkey:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-logstash.key
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
# End -- Elastic Fleet Logstash Input Cert
|
||||
{% endif %} # endif is for not including HeavyNodes
|
||||
|
||||
# Start -- Elastic Fleet Node - Logstash Lumberjack Input / Output
|
||||
# Cert needed on: Managers, Receivers
|
||||
etc_elasticfleetlumberjack_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/elasticfleet-lumberjack.key
|
||||
- bits: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/elasticfleet-lumberjack.key') -%}
|
||||
- prereq:
|
||||
- x509: etc_elasticfleetlumberjack_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
etc_elasticfleetlumberjack_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/elasticfleet-lumberjack.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: elasticfleet
|
||||
- private_key: /etc/pki/elasticfleet-lumberjack.key
|
||||
- CN: {{ GLOBALS.node_ip }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-lumberjack.key -topk8 -out /etc/pki/elasticfleet-lumberjack.p8 -nocrypt"
|
||||
- onchanges:
|
||||
- x509: etc_elasticfleetlumberjack_key
|
||||
|
||||
eflogstashlumberjackperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-lumberjack.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
chownilogstashelasticfleetlumberjackp8:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-lumberjack.p8
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
chownilogstashelasticfleetlogstashlumberjackcrt:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-lumberjack.crt
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
chownilogstashelasticfleetlogstashlumberjackkey:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/elasticfleet-lumberjack.key
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
# End -- Elastic Fleet Node - Logstash Lumberjack Input / Output
|
||||
{% endif %}
|
||||
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-receiver'] %}
|
||||
etc_filebeat_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/filebeat.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/filebeat.key') -%}
|
||||
- prereq:
|
||||
- x509: etc_filebeat_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
# Request a cert and drop it where it needs to go to be distributed
|
||||
etc_filebeat_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/filebeat.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: filebeat
|
||||
- private_key: /etc/pki/filebeat.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs8 -in /etc/pki/filebeat.key -topk8 -out /etc/pki/filebeat.p8 -nocrypt"
|
||||
- onchanges:
|
||||
- x509: etc_filebeat_key
|
||||
|
||||
fbperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/filebeat.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
logstash_filebeat_p8:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/filebeat.p8
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
{% if grains.role not in ['so-heavynode', 'so-receiver'] %}
|
||||
# Create Symlinks to the keys so I can distribute it to all the things
|
||||
filebeatdir:
|
||||
file.directory:
|
||||
- name: /opt/so/saltstack/local/salt/filebeat/files
|
||||
- makedirs: True
|
||||
|
||||
fbkeylink:
|
||||
file.symlink:
|
||||
- name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.p8
|
||||
- target: /etc/pki/filebeat.p8
|
||||
- user: socore
|
||||
- group: socore
|
||||
|
||||
fbcrtlink:
|
||||
file.symlink:
|
||||
- name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.crt
|
||||
- target: /etc/pki/filebeat.crt
|
||||
- user: socore
|
||||
- group: socore
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if GLOBALS.is_manager or GLOBALS.role in ['so-sensor', 'so-searchnode', 'so-heavynode', 'so-fleet', 'so-idh', 'so-receiver'] %}
|
||||
|
||||
fbcertdir:
|
||||
file.directory:
|
||||
- name: /opt/so/conf/filebeat/etc/pki
|
||||
- makedirs: True
|
||||
|
||||
conf_filebeat_key:
|
||||
x509.private_key_managed:
|
||||
- name: /opt/so/conf/filebeat/etc/pki/filebeat.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/opt/so/conf/filebeat/etc/pki/filebeat.key') -%}
|
||||
- prereq:
|
||||
- x509: conf_filebeat_crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
# Request a cert and drop it where it needs to go to be distributed
|
||||
conf_filebeat_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /opt/so/conf/filebeat/etc/pki/filebeat.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: filebeat
|
||||
- private_key: /opt/so/conf/filebeat/etc/pki/filebeat.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
|
||||
# Convert the key to pkcs#8 so logstash will work correctly.
|
||||
filebeatpkcs:
|
||||
cmd.run:
|
||||
- name: "/usr/bin/openssl pkcs8 -in /opt/so/conf/filebeat/etc/pki/filebeat.key -topk8 -out /opt/so/conf/filebeat/etc/pki/filebeat.p8 -passout pass:"
|
||||
- onchanges:
|
||||
- x509: conf_filebeat_key
|
||||
|
||||
filebeatkeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /opt/so/conf/filebeat/etc/pki/filebeat.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
chownfilebeatp8:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /opt/so/conf/filebeat/etc/pki/filebeat.p8
|
||||
- mode: 640
|
||||
- user: 931
|
||||
- group: 939
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -1,3 +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.
|
||||
|
||||
elastic_curl_config_distributed:
|
||||
file.managed:
|
||||
- name: /opt/so/saltstack/local/salt/elasticsearch/curl.config
|
||||
|
||||
@@ -214,7 +214,7 @@ git_config_set_safe_dirs:
|
||||
|
||||
surinsmrulesdir:
|
||||
file.directory:
|
||||
- name: /nsm/rules/suricata
|
||||
- name: /nsm/rules/suricata/etopen
|
||||
- user: 939
|
||||
- group: 939
|
||||
- makedirs: True
|
||||
|
||||
@@ -1,3 +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.
|
||||
|
||||
kibana_curl_config_distributed:
|
||||
file.managed:
|
||||
- name: /opt/so/conf/kibana/curl.config
|
||||
@@ -5,4 +10,4 @@ kibana_curl_config_distributed:
|
||||
- template: jinja
|
||||
- mode: 600
|
||||
- show_changes: False
|
||||
- makedirs: True
|
||||
- makedirs: True
|
||||
|
||||
@@ -1,3 +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.
|
||||
|
||||
include:
|
||||
- elasticsearch.auth
|
||||
- kratos
|
||||
|
||||
@@ -133,7 +133,7 @@ function getinstallinfo() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
source <(echo $INSTALLVARS)
|
||||
export $(echo "$INSTALLVARS" | xargs)
|
||||
if [ $? -ne 0 ]; then
|
||||
log "ERROR" "Failed to source install variables"
|
||||
return 1
|
||||
@@ -716,6 +716,18 @@ function checkMine() {
|
||||
}
|
||||
}
|
||||
|
||||
function create_ca_pillar() {
|
||||
local capillar=/opt/so/saltstack/local/pillar/ca/init.sls
|
||||
printf '%s\n'\
|
||||
"ca:"\
|
||||
" server: $MINION_ID"\
|
||||
" " > $capillar
|
||||
if [ $? -ne 0 ]; then
|
||||
log "ERROR" "Failed to add $MINION_ID to $capillar"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function createEVAL() {
|
||||
log "INFO" "Creating EVAL configuration for minion $MINION_ID"
|
||||
is_pcaplimit=true
|
||||
@@ -827,7 +839,6 @@ function createHEAVYNODE() {
|
||||
add_elastic_agent_to_minion || return 1
|
||||
add_sensor_to_minion || return 1
|
||||
add_strelka_to_minion || return 1
|
||||
add_redis_to_minion || return 1
|
||||
add_telegraf_to_minion || return 1
|
||||
}
|
||||
|
||||
@@ -1013,6 +1024,7 @@ function setupMinionFiles() {
|
||||
managers=("EVAL" "STANDALONE" "IMPORT" "MANAGER" "MANAGERSEARCH")
|
||||
if echo "${managers[@]}" | grep -qw "$NODETYPE"; then
|
||||
add_sensoroni_with_analyze_to_minion || return 1
|
||||
create_ca_pillar || return 1
|
||||
else
|
||||
add_sensoroni_to_minion || return 1
|
||||
fi
|
||||
|
||||
@@ -9,6 +9,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
import yaml
|
||||
import json
|
||||
|
||||
lockFile = "/tmp/so-yaml.lock"
|
||||
|
||||
@@ -16,19 +17,24 @@ lockFile = "/tmp/so-yaml.lock"
|
||||
def showUsage(args):
|
||||
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]), file=sys.stderr)
|
||||
print(' General commands:', file=sys.stderr)
|
||||
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||
print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
||||
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
||||
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
||||
print(' replace - Replaces (or adds) a new key and set its value. Requires KEY and VALUE args.', file=sys.stderr)
|
||||
print(' help - Prints this usage information.', file=sys.stderr)
|
||||
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||
print(' appendlistobject - Append an object to a yaml list key. Requires KEY and JSON_OBJECT args.', file=sys.stderr)
|
||||
print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||
print(' replacelistobject - Replace a list object based on a condition. Requires KEY, CONDITION_FIELD, CONDITION_VALUE, and JSON_OBJECT args.', file=sys.stderr)
|
||||
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
||||
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
||||
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
||||
print(' replace - Replaces (or adds) a new key and set its value. Requires KEY and VALUE args.', file=sys.stderr)
|
||||
print(' help - Prints this usage information.', file=sys.stderr)
|
||||
print('', file=sys.stderr)
|
||||
print(' Where:', file=sys.stderr)
|
||||
print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr)
|
||||
print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr)
|
||||
print(' VALUE - Value to set for a given key. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||
print(' LISTITEM - Item to append to a given key\'s list value. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||
print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr)
|
||||
print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr)
|
||||
print(' VALUE - Value to set for a given key. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||
print(' LISTITEM - Item to append to a given key\'s list value. Can be a literal value or file:<path> to load from a YAML file.', file=sys.stderr)
|
||||
print(' JSON_OBJECT - JSON string representing an object to append to a list.', file=sys.stderr)
|
||||
print(' CONDITION_FIELD - Field name to match in list items (e.g., "name").', file=sys.stderr)
|
||||
print(' CONDITION_VALUE - Value to match for the condition field.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -122,6 +128,52 @@ def append(args):
|
||||
return 0
|
||||
|
||||
|
||||
def appendListObjectItem(content, key, listObject):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
appendListObjectItem(content[pieces[0]], pieces[1], listObject)
|
||||
else:
|
||||
try:
|
||||
if not isinstance(content[key], list):
|
||||
raise AttributeError("Value is not a list")
|
||||
content[key].append(listObject)
|
||||
except AttributeError:
|
||||
print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr)
|
||||
return 1
|
||||
except KeyError:
|
||||
print("The key provided does not exist. No action was taken on the file.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
def appendlistobject(args):
|
||||
if len(args) != 3:
|
||||
print('Missing filename, key arg, or JSON object to append', file=sys.stderr)
|
||||
showUsage(None)
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
key = args[1]
|
||||
jsonString = args[2]
|
||||
|
||||
try:
|
||||
# Parse the JSON string into a Python dictionary
|
||||
listObject = json.loads(jsonString)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'Invalid JSON string: {e}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Verify that the parsed content is a dictionary (object)
|
||||
if not isinstance(listObject, dict):
|
||||
print('The JSON string must represent an object (dictionary), not an array or primitive value.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
content = loadYaml(filename)
|
||||
appendListObjectItem(content, key, listObject)
|
||||
writeYaml(filename, content)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def removelistitem(args):
|
||||
if len(args) != 3:
|
||||
print('Missing filename, key arg, or list item to remove', file=sys.stderr)
|
||||
@@ -139,6 +191,68 @@ def removelistitem(args):
|
||||
return 0
|
||||
|
||||
|
||||
def replaceListObjectByCondition(content, key, conditionField, conditionValue, newObject):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
replaceListObjectByCondition(content[pieces[0]], pieces[1], conditionField, conditionValue, newObject)
|
||||
else:
|
||||
try:
|
||||
if not isinstance(content[key], list):
|
||||
raise AttributeError("Value is not a list")
|
||||
|
||||
# Find and replace the item that matches the condition
|
||||
found = False
|
||||
for i, item in enumerate(content[key]):
|
||||
if isinstance(item, dict) and item.get(conditionField) == conditionValue:
|
||||
content[key][i] = newObject
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
print(f"No list item found with {conditionField}={conditionValue}. No action was taken on the file.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
except AttributeError:
|
||||
print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr)
|
||||
return 1
|
||||
except KeyError:
|
||||
print("The key provided does not exist. No action was taken on the file.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
def replacelistobject(args):
|
||||
if len(args) != 5:
|
||||
print('Missing filename, key arg, condition field, condition value, or JSON object', file=sys.stderr)
|
||||
showUsage(None)
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
key = args[1]
|
||||
conditionField = args[2]
|
||||
conditionValue = args[3]
|
||||
jsonString = args[4]
|
||||
|
||||
try:
|
||||
# Parse the JSON string into a Python dictionary
|
||||
newObject = json.loads(jsonString)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'Invalid JSON string: {e}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Verify that the parsed content is a dictionary (object)
|
||||
if not isinstance(newObject, dict):
|
||||
print('The JSON string must represent an object (dictionary), not an array or primitive value.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
content = loadYaml(filename)
|
||||
result = replaceListObjectByCondition(content, key, conditionField, conditionValue, newObject)
|
||||
|
||||
if result != 1:
|
||||
writeYaml(filename, content)
|
||||
|
||||
return result if result is not None else 0
|
||||
|
||||
|
||||
def addKey(content, key, value):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
@@ -247,7 +361,9 @@ def main():
|
||||
"help": showUsage,
|
||||
"add": add,
|
||||
"append": append,
|
||||
"appendlistobject": appendlistobject,
|
||||
"removelistitem": removelistitem,
|
||||
"replacelistobject": replacelistobject,
|
||||
"get": get,
|
||||
"remove": remove,
|
||||
"replace": replace,
|
||||
|
||||
@@ -580,3 +580,340 @@ class TestRemoveListItem(unittest.TestCase):
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
|
||||
class TestAppendListObject(unittest.TestCase):
|
||||
|
||||
def test_appendlistobject_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.appendlistobject(["file", "key"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn("Missing filename, key arg, or JSON object to append", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123 }, key2: [{name: item1, value: 10}]}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"name": "item2", "value": 20}'
|
||||
soyaml.appendlistobject([filename, "key2", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\nkey2:\n- name: item1\n value: 10\n- name: item2\n value: 20\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_appendlistobject_nested(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: [{name: a, id: 1}], child2: abc }, key2: false}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"name": "b", "id": 2}'
|
||||
soyaml.appendlistobject([filename, "key1.child1", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
# YAML doesn't guarantee key order in dictionaries, so check for content
|
||||
self.assertIn("child1:", actual)
|
||||
self.assertIn("name: a", actual)
|
||||
self.assertIn("id: 1", actual)
|
||||
self.assertIn("name: b", actual)
|
||||
self.assertIn("id: 2", actual)
|
||||
self.assertIn("child2: abc", actual)
|
||||
self.assertIn("key2: false", actual)
|
||||
|
||||
def test_appendlistobject_nested_deep(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [{x: 1}] } }, key2: false}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"x": 2, "y": 3}'
|
||||
soyaml.appendlistobject([filename, "key1.child2.deep2", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - x: 1\n - x: 2\n y: 3\nkey2: false\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_appendlistobject_invalid_json(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
result = soyaml.appendlistobject([filename, "key1", "{invalid json"])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("Invalid JSON string:", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_not_dict(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
# Try to append an array instead of an object
|
||||
result = soyaml.appendlistobject([filename, "key1", "[1, 2, 3]"])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_not_dict_primitive(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
# Try to append a primitive value
|
||||
result = soyaml.appendlistobject([filename, "key1", "123"])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_key_noexist(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "appendlistobject", filename, "key2", '{"name": "item2"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_key_noexist_deep(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: [{name: a}] }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "appendlistobject", filename, "key1.child2", '{"name": "b"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_key_nonlist(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123 }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "appendlistobject", filename, "key1", '{"name": "item"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_appendlistobject_key_nonlist_deep(self):
|
||||
filename = "/tmp/so-yaml_test-appendlistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45 } }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "appendlistobject", filename, "key1.child2.deep1", '{"name": "item"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
|
||||
class TestReplaceListObject(unittest.TestCase):
|
||||
|
||||
def test_replacelistobject_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.replacelistobject(["file", "key", "field"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn("Missing filename, key arg, condition field, condition value, or JSON object", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"name": "item2", "value": 25, "extra": "field"}'
|
||||
soyaml.replacelistobject([filename, "key1", "name", "item2", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n- name: item1\n value: 10\n- extra: field\n name: item2\n value: 25\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replacelistobject_nested(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: [{id: '1', status: active}, {id: '2', status: inactive}] }}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"id": "2", "status": "active", "updated": true}'
|
||||
soyaml.replacelistobject([filename, "key1.child1", "id", "2", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1:\n - id: '1'\n status: active\n - id: '2'\n status: active\n updated: true\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replacelistobject_nested_deep(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [{name: a, val: 1}, {name: b, val: 2}] } }}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"name": "b", "val": 99}'
|
||||
soyaml.replacelistobject([filename, "key1.child2.deep2", "name", "b", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - name: a\n val: 1\n - name: b\n val: 99\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replacelistobject_invalid_json(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
result = soyaml.replacelistobject([filename, "key1", "name", "item1", "{invalid json"])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("Invalid JSON string:", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_not_dict(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
result = soyaml.replacelistobject([filename, "key1", "name", "item1", "[1, 2, 3]"])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_condition_not_found(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
json_obj = '{"name": "item3", "value": 30}'
|
||||
result = soyaml.replacelistobject([filename, "key1", "name", "item3", json_obj])
|
||||
self.assertEqual(result, 1)
|
||||
self.assertIn("No list item found with name=item3", mock_stderr.getvalue())
|
||||
|
||||
# Verify file was not modified
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
self.assertIn("item1", actual)
|
||||
self.assertIn("item2", actual)
|
||||
self.assertNotIn("item3", actual)
|
||||
|
||||
def test_replacelistobject_key_noexist(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1}]}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "replacelistobject", filename, "key2", "name", "item1", '{"name": "item2"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_key_noexist_deep(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: [{name: a}] }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "replacelistobject", filename, "key1.child2", "name", "a", '{"name": "b"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_key_nonlist(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123 }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "replacelistobject", filename, "key1", "name", "item", '{"name": "item"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_key_nonlist_deep(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45 } }}")
|
||||
file.close()
|
||||
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||
sys.argv = ["cmd", "replacelistobject", filename, "key1.child2.deep1", "name", "item", '{"name": "item"}']
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||
|
||||
def test_replacelistobject_string_condition_value(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"name": "item1", "value": 15}'
|
||||
soyaml.replacelistobject([filename, "key1", "name", "item1", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n- name: item1\n value: 15\n- name: item2\n value: 20\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replacelistobject_numeric_condition_value(self):
|
||||
filename = "/tmp/so-yaml_test-replacelistobject.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: [{id: '1', status: active}, {id: '2', status: inactive}]}")
|
||||
file.close()
|
||||
|
||||
json_obj = '{"id": "1", "status": "updated"}'
|
||||
soyaml.replacelistobject([filename, "key1", "id", "1", json_obj])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n- id: '1'\n status: updated\n- id: '2'\n status: inactive\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@@ -87,6 +87,16 @@ check_err() {
|
||||
113)
|
||||
echo 'No route to host'
|
||||
;;
|
||||
160)
|
||||
echo 'Incompatiable Elasticsearch upgrade'
|
||||
;;
|
||||
161)
|
||||
echo 'Required intermediate Elasticsearch upgrade not complete'
|
||||
;;
|
||||
170)
|
||||
echo "Intermediate upgrade completed successfully to $next_step_so_version, but next soup to Security Onion $originally_requested_so_version could not be started automatically."
|
||||
echo "Start soup again manually to continue the upgrade to Security Onion $originally_requested_so_version."
|
||||
;;
|
||||
*)
|
||||
echo 'Unhandled error'
|
||||
echo "$err_msg"
|
||||
@@ -148,7 +158,7 @@ EOF
|
||||
echo "Ensure you verify the ISO that you downloaded."
|
||||
exit 0
|
||||
else
|
||||
echo "Device has been mounted!"
|
||||
echo "Device has been mounted! $(cat /tmp/soagupdate/SecurityOnion/VERSION)"
|
||||
fi
|
||||
else
|
||||
echo "Could not find Security Onion ISO content at ${ISOLOC}"
|
||||
@@ -319,6 +329,19 @@ clone_to_tmp() {
|
||||
fi
|
||||
}
|
||||
|
||||
# there is a function like this in so-minion, but we cannot source it since args required for so-minion
|
||||
create_ca_pillar() {
|
||||
local ca_pillar_dir="/opt/so/saltstack/local/pillar/ca"
|
||||
local ca_pillar_file="${ca_pillar_dir}/init.sls"
|
||||
|
||||
echo "Updating CA pillar configuration"
|
||||
mkdir -p "$ca_pillar_dir"
|
||||
echo "ca: {}" > "$ca_pillar_file"
|
||||
|
||||
so-yaml.py add "$ca_pillar_file" ca.server "$MINIONID"
|
||||
chown -R socore:socore "$ca_pillar_dir"
|
||||
}
|
||||
|
||||
disable_logstash_heavynodes() {
|
||||
c=0
|
||||
printf "\nChecking for heavynodes and disabling Logstash if they exist\n"
|
||||
@@ -334,6 +357,22 @@ disable_logstash_heavynodes() {
|
||||
done
|
||||
}
|
||||
|
||||
disable_redis_heavynodes() {
|
||||
local c=0
|
||||
printf "\nChecking for heavynodes and disabling Redis if they exist\n"
|
||||
for file in /opt/so/saltstack/local/pillar/minions/*.sls; do
|
||||
if [[ "$file" =~ "_heavynode.sls" && ! "$file" =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then
|
||||
c=1
|
||||
echo "Disabling Redis for: $file"
|
||||
so-yaml.py replace "$file" redis.enabled False
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$c" != 0 ]]; then
|
||||
FINAL_MESSAGE_QUEUE+=("Redis has been disabled on all heavynodes.")
|
||||
fi
|
||||
}
|
||||
|
||||
enable_highstate() {
|
||||
echo "Enabling highstate."
|
||||
salt-call state.enable highstate -l info --local
|
||||
@@ -362,7 +401,6 @@ masterlock() {
|
||||
echo "base:" > $TOPFILE
|
||||
echo " $MINIONID:" >> $TOPFILE
|
||||
echo " - ca" >> $TOPFILE
|
||||
echo " - ssl" >> $TOPFILE
|
||||
echo " - elasticsearch" >> $TOPFILE
|
||||
}
|
||||
|
||||
@@ -427,6 +465,8 @@ preupgrade_changes() {
|
||||
[[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180
|
||||
[[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190
|
||||
[[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200
|
||||
[[ "$INSTALLEDVERSION" == 2.4.200 ]] && up_to_2.4.201
|
||||
[[ "$INSTALLEDVERSION" == 2.4.201 ]] && up_to_2.4.210
|
||||
true
|
||||
}
|
||||
|
||||
@@ -441,24 +481,26 @@ postupgrade_changes() {
|
||||
[[ "$POSTVERSION" == 2.4.10 ]] && post_to_2.4.20
|
||||
[[ "$POSTVERSION" == 2.4.20 ]] && post_to_2.4.30
|
||||
[[ "$POSTVERSION" == 2.4.30 ]] && post_to_2.4.40
|
||||
[[ "$POSTVERSION" == 2.4.40 ]] && post_to_2.4.50
|
||||
[[ "$POSTVERSION" == 2.4.50 ]] && post_to_2.4.60
|
||||
[[ "$POSTVERSION" == 2.4.60 ]] && post_to_2.4.70
|
||||
[[ "$POSTVERSION" == 2.4.70 ]] && post_to_2.4.80
|
||||
[[ "$POSTVERSION" == 2.4.80 ]] && post_to_2.4.90
|
||||
[[ "$POSTVERSION" == 2.4.90 ]] && post_to_2.4.100
|
||||
[[ "$POSTVERSION" == 2.4.100 ]] && post_to_2.4.110
|
||||
[[ "$POSTVERSION" == 2.4.40 ]] && post_to_2.4.50
|
||||
[[ "$POSTVERSION" == 2.4.50 ]] && post_to_2.4.60
|
||||
[[ "$POSTVERSION" == 2.4.60 ]] && post_to_2.4.70
|
||||
[[ "$POSTVERSION" == 2.4.70 ]] && post_to_2.4.80
|
||||
[[ "$POSTVERSION" == 2.4.80 ]] && post_to_2.4.90
|
||||
[[ "$POSTVERSION" == 2.4.90 ]] && post_to_2.4.100
|
||||
[[ "$POSTVERSION" == 2.4.100 ]] && post_to_2.4.110
|
||||
[[ "$POSTVERSION" == 2.4.110 ]] && post_to_2.4.111
|
||||
[[ "$POSTVERSION" == 2.4.111 ]] && post_to_2.4.120
|
||||
[[ "$POSTVERSION" == 2.4.120 ]] && post_to_2.4.130
|
||||
[[ "$POSTVERSION" == 2.4.130 ]] && post_to_2.4.140
|
||||
[[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141
|
||||
[[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150
|
||||
[[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160
|
||||
[[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170
|
||||
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
||||
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
||||
[[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200
|
||||
[[ "$POSTVERSION" == 2.4.111 ]] && post_to_2.4.120
|
||||
[[ "$POSTVERSION" == 2.4.120 ]] && post_to_2.4.130
|
||||
[[ "$POSTVERSION" == 2.4.130 ]] && post_to_2.4.140
|
||||
[[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141
|
||||
[[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150
|
||||
[[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160
|
||||
[[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170
|
||||
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
||||
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
||||
[[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200
|
||||
[[ "$POSTVERSION" == 2.4.200 ]] && post_to_2.4.201
|
||||
[[ "$POSTVERSION" == 2.4.201 ]] && post_to_2.4.210
|
||||
true
|
||||
}
|
||||
|
||||
@@ -615,9 +657,6 @@ post_to_2.4.180() {
|
||||
}
|
||||
|
||||
post_to_2.4.190() {
|
||||
echo "Regenerating Elastic Agent Installers"
|
||||
/sbin/so-elastic-agent-gen-installers
|
||||
|
||||
# Only need to update import / eval nodes
|
||||
if [[ "$MINION_ROLE" == "import" ]] || [[ "$MINION_ROLE" == "eval" ]]; then
|
||||
update_import_fleet_output
|
||||
@@ -645,6 +684,26 @@ post_to_2.4.200() {
|
||||
POSTVERSION=2.4.200
|
||||
}
|
||||
|
||||
post_to_2.4.201() {
|
||||
echo "Nothing to apply"
|
||||
POSTVERSION=2.4.201
|
||||
}
|
||||
|
||||
post_to_2.4.210() {
|
||||
echo "Rolling over Kratos index to apply new index template"
|
||||
|
||||
rollover_index "logs-kratos-so"
|
||||
|
||||
disable_redis_heavynodes
|
||||
|
||||
initialize_elasticsearch_indices "so-case so-casehistory so-assistant-session so-assistant-chat"
|
||||
|
||||
echo "Regenerating Elastic Agent Installers"
|
||||
/sbin/so-elastic-agent-gen-installers
|
||||
|
||||
POSTVERSION=2.4.210
|
||||
}
|
||||
|
||||
repo_sync() {
|
||||
echo "Sync the local repo."
|
||||
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
||||
@@ -906,9 +965,7 @@ up_to_2.4.180() {
|
||||
}
|
||||
|
||||
up_to_2.4.190() {
|
||||
# Elastic Update for this release, so download Elastic Agent files
|
||||
determine_elastic_agent_upgrade
|
||||
|
||||
echo "Nothing to do for 2.4.190"
|
||||
INSTALLEDVERSION=2.4.190
|
||||
}
|
||||
|
||||
@@ -921,6 +978,22 @@ up_to_2.4.200() {
|
||||
INSTALLEDVERSION=2.4.200
|
||||
}
|
||||
|
||||
up_to_2.4.201() {
|
||||
echo "Nothing to do for 2.4.201"
|
||||
|
||||
INSTALLEDVERSION=2.4.201
|
||||
}
|
||||
|
||||
up_to_2.4.210() {
|
||||
# Elastic Update for this release, so download Elastic Agent files
|
||||
determine_elastic_agent_upgrade
|
||||
create_ca_pillar
|
||||
# This state is used to deal with the breaking change introduced in 3006.17 - https://docs.saltproject.io/en/3006/topics/releases/3006.17.html
|
||||
# This is the only way the state is called so we can use concurrent=True
|
||||
salt-call state.apply salt.master.add_minimum_auth_version --file-root=$UPDATE_DIR/salt --local concurrent=True
|
||||
INSTALLEDVERSION=2.4.210
|
||||
}
|
||||
|
||||
add_hydra_pillars() {
|
||||
mkdir -p /opt/so/saltstack/local/pillar/hydra
|
||||
touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls
|
||||
@@ -1113,47 +1186,47 @@ suricata_idstools_removal_pre() {
|
||||
install -d -o 939 -g 939 -m 755 /opt/so/conf/soc/fingerprints
|
||||
install -o 939 -g 939 -m 644 /dev/null /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||
cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF
|
||||
Suricata ruleset sync is blocked until this file is removed. Make sure that you have manually added any custom Suricata rulesets via SOC config - review the documentation for more details: securityonion.net/docs
|
||||
Suricata ruleset sync is blocked until this file is removed. **CRITICAL** Make sure that you have manually added any custom Suricata rulesets via SOC config before removing this file - review the documentation for more details: https://docs.securityonion.net/en/2.4/nids.html#sync-block
|
||||
EOF
|
||||
|
||||
# Remove possible symlink & create salt local rules dir
|
||||
[ -L /opt/so/saltstack/local/salt/suricata/rules ] && rm -f /opt/so/saltstack/local/salt/suricata/rules
|
||||
install -d -o 939 -g 939 /opt/so/saltstack/local/salt/suricata/rules/ || echo "Failed to create Suricata local rules directory"
|
||||
|
||||
# Backup custom rules & overrides
|
||||
mkdir -p /nsm/backup/detections-migration/2-4-200
|
||||
cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200
|
||||
cp /opt/so/conf/idstools/etc/rulecat.conf /nsm/backup/detections-migration/2-4-200
|
||||
|
||||
if [[ -f /opt/so/conf/soc/so-detections-backup.py ]]; then
|
||||
python3 /opt/so/conf/soc/so-detections-backup.py
|
||||
# Backup so-detection index via reindex
|
||||
echo "Creating sos-backup index template..."
|
||||
template_result=$(/sbin/so-elasticsearch-query '_index_template/sos-backup' -X PUT \
|
||||
--retry 5 --retry-delay 15 --retry-all-errors \
|
||||
-d '{"index_patterns":["sos-backup-*"],"priority":501,"template":{"settings":{"index":{"number_of_replicas":0,"number_of_shards":1}}}}')
|
||||
|
||||
# Verify backup by comparing counts
|
||||
echo "Verifying detection overrides backup..."
|
||||
es_override_count=$(/sbin/so-elasticsearch-query 'so-detection/_count' \
|
||||
-d '{"query": {"bool": {"must": [{"exists": {"field": "so_detection.overrides"}}]}}}' | jq -r '.count') || {
|
||||
echo " Error: Failed to query Elasticsearch for override count"
|
||||
exit 1
|
||||
}
|
||||
if [[ -z "$template_result" ]] || ! echo "$template_result" | jq -e '.acknowledged == true' > /dev/null 2>&1; then
|
||||
echo "Error: Failed to create sos-backup index template"
|
||||
echo "$template_result"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$es_override_count" =~ ^[0-9]+$ ]]; then
|
||||
echo " Error: Invalid override count from Elasticsearch: '$es_override_count'"
|
||||
exit 1
|
||||
fi
|
||||
BACKUP_INDEX="sos-backup-detection-$(date +%Y%m%d-%H%M%S)"
|
||||
echo "Backing up so-detection index to $BACKUP_INDEX..."
|
||||
reindex_result=$(/sbin/so-elasticsearch-query '_reindex?wait_for_completion=true' \
|
||||
--retry 5 --retry-delay 15 --retry-all-errors \
|
||||
-X POST -d "{\"source\": {\"index\": \"so-detection\"}, \"dest\": {\"index\": \"$BACKUP_INDEX\"}}")
|
||||
|
||||
backup_override_count=$(find /nsm/backup/detections/repo/*/overrides -type f 2>/dev/null | wc -l)
|
||||
|
||||
echo " Elasticsearch overrides: $es_override_count"
|
||||
echo " Backed up overrides: $backup_override_count"
|
||||
|
||||
if [[ "$es_override_count" -gt 0 ]]; then
|
||||
if [[ "$backup_override_count" -gt 0 ]]; then
|
||||
echo " Override backup verified successfully"
|
||||
else
|
||||
echo " Error: Elasticsearch has $es_override_count overrides but backup has 0 files"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " No overrides to backup"
|
||||
fi
|
||||
if [[ -z "$reindex_result" ]]; then
|
||||
echo "Error: Backup of detections failed - no response from Elasticsearch"
|
||||
exit 1
|
||||
elif echo "$reindex_result" | jq -e '.created >= 0' > /dev/null 2>&1; then
|
||||
echo "Backup complete: $(echo "$reindex_result" | jq -r '.created') documents copied"
|
||||
elif echo "$reindex_result" | grep -q "index_not_found_exception"; then
|
||||
echo "so-detection index does not exist, skipping backup"
|
||||
else
|
||||
echo "SOC Detections backup script not found, skipping detection backup"
|
||||
echo "Error: Backup of detections failed"
|
||||
echo "$reindex_result"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
@@ -1174,11 +1247,12 @@ hash_normalized_file() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
sed -E \
|
||||
# Ensure trailing newline for consistent hashing regardless of source file
|
||||
{ sed -E \
|
||||
-e 's/^[[:space:]]+//; s/[[:space:]]+$//' \
|
||||
-e '/^$/d' \
|
||||
-e 's|--url=http://[^:]+:7788|--url=http://MANAGER:7788|' \
|
||||
"$file" | sha256sum | awk '{print $1}'
|
||||
"$file"; echo; } | sed '/^$/d' | sha256sum | awk '{print $1}'
|
||||
}
|
||||
|
||||
# Known-default hashes for so-rule-update (ETOPEN ruleset)
|
||||
@@ -1274,6 +1348,13 @@ custom_found=0
|
||||
check_config_file "$SO_RULE_UPDATE" "KNOWN_SO_RULE_UPDATE_HASHES" || custom_found=1
|
||||
check_config_file "$RULECAT_CONF" "KNOWN_RULECAT_CONF_HASHES" || custom_found=1
|
||||
|
||||
# Check for ETPRO rules on airgap systems
|
||||
if [[ $is_airgap -eq 0 ]] && grep -q 'ETPRO ' /nsm/rules/suricata/emerging-all.rules 2>/dev/null; then
|
||||
echo "ETPRO rules detected on airgap system - custom configuration"
|
||||
echo "ETPRO rules detected on Airgap in /nsm/rules/suricata/emerging-all.rules" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||
custom_found=1
|
||||
fi
|
||||
|
||||
# If no custom configs found, remove syncBlock
|
||||
if [[ $custom_found -eq 0 ]]; then
|
||||
echo "idstools migration completed successfully - removing Suricata engine syncBlock"
|
||||
@@ -1297,9 +1378,9 @@ if [ -n "$(docker ps -q -f name=^so-idstools$)" ]; then
|
||||
fi
|
||||
|
||||
echo "Removing idstools symlink and scripts..."
|
||||
rm /opt/so/saltstack/local/salt/suricata/rules
|
||||
rm -rf /usr/sbin/so-idstools*
|
||||
sed -i '/^#\?so-idstools$/d' /opt/so/conf/so-status/so-status.conf
|
||||
crontab -l | grep -v 'so-rule-update' | crontab -
|
||||
|
||||
# Backup the salt master config & manager pillar before editing it
|
||||
cp /opt/so/saltstack/local/pillar/minions/$MINIONID.sls /nsm/backup/detections-migration/2-4-200/
|
||||
@@ -1355,7 +1436,7 @@ unmount_update() {
|
||||
|
||||
update_airgap_rules() {
|
||||
# Copy the rules over to update them for airgap.
|
||||
rsync -a $UPDATE_DIR/agrules/suricata/* /nsm/rules/suricata/
|
||||
rsync -a --delete $UPDATE_DIR/agrules/suricata/ /nsm/rules/suricata/etopen/
|
||||
rsync -a $UPDATE_DIR/agrules/detect-sigma/* /nsm/rules/detect-sigma/
|
||||
rsync -a $UPDATE_DIR/agrules/detect-yara/* /nsm/rules/detect-yara/
|
||||
# Copy the securityonion-resorces repo over for SOC Detection Summaries and checkout the published summaries branch
|
||||
@@ -1604,6 +1685,355 @@ verify_latest_update_script() {
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
verify_es_version_compatibility() {
|
||||
|
||||
local es_required_version_statefile_base="/opt/so/state/so_es_required_upgrade_version"
|
||||
local es_verification_script="/tmp/so_intermediate_upgrade_verification.sh"
|
||||
local is_active_intermediate_upgrade=1
|
||||
# supported upgrade paths for SO-ES versions
|
||||
declare -A es_upgrade_map=(
|
||||
["8.14.3"]="8.17.3 8.18.4 8.18.6 8.18.8"
|
||||
["8.17.3"]="8.18.4 8.18.6 8.18.8"
|
||||
["8.18.4"]="8.18.6 8.18.8 9.0.8"
|
||||
["8.18.6"]="8.18.8 9.0.8"
|
||||
["8.18.8"]="9.0.8"
|
||||
)
|
||||
|
||||
# Elasticsearch MUST upgrade through these versions
|
||||
declare -A es_to_so_version=(
|
||||
["8.18.8"]="2.4.190-20251024"
|
||||
)
|
||||
|
||||
# Get current Elasticsearch version
|
||||
if es_version_raw=$(so-elasticsearch-query / --fail --retry 5 --retry-delay 10); then
|
||||
es_version=$(echo "$es_version_raw" | jq -r '.version.number' )
|
||||
else
|
||||
echo "Could not determine current Elasticsearch version to validate compatibility with post soup Elasticsearch version."
|
||||
|
||||
exit 160
|
||||
fi
|
||||
|
||||
if ! target_es_version_raw=$(so-yaml.py get $UPDATE_DIR/salt/elasticsearch/defaults.yaml elasticsearch.version); then
|
||||
# so-yaml.py failed to get the ES version from upgrade versions elasticsearch/defaults.yaml file. Likely they are upgrading to an SO version older than 2.4.110 prior to the ES version pinning and should be OKAY to continue with the upgrade.
|
||||
|
||||
# if so-yaml.py failed to get the ES version AND the version we are upgrading to is newer than 2.4.110 then we should bail
|
||||
if [[ $(cat $UPDATE_DIR/VERSION | cut -d'.' -f3) > 110 ]]; then
|
||||
echo "Couldn't determine the target Elasticsearch version (post soup version) to ensure compatibility with current Elasticsearch version. Exiting"
|
||||
|
||||
exit 160
|
||||
fi
|
||||
|
||||
# allow upgrade to version < 2.4.110 without checking ES version compatibility
|
||||
return 0
|
||||
else
|
||||
target_es_version=$(sed -n '1p' <<< "$target_es_version_raw")
|
||||
fi
|
||||
|
||||
for statefile in "${es_required_version_statefile_base}"-*; do
|
||||
[[ -f $statefile ]] || continue
|
||||
|
||||
local es_required_version_statefile_value=$(cat "$statefile")
|
||||
|
||||
if [[ "$es_required_version_statefile_value" == "$target_es_version" ]]; then
|
||||
echo "Intermediate upgrade to ES $target_es_version is in progress. Skipping Elasticsearch version compatibility check."
|
||||
is_active_intermediate_upgrade=0
|
||||
continue
|
||||
fi
|
||||
|
||||
# use sort to check if es_required_statefile_value is < the current es_version.
|
||||
if [[ "$(printf '%s\n' $es_required_version_statefile_value $es_version | sort -V | head -n1)" == "$es_required_version_statefile_value" ]]; then
|
||||
rm -f "$statefile"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ ! -f "$es_verification_script" ]]; then
|
||||
create_intermediate_upgrade_verification_script "$es_verification_script"
|
||||
fi
|
||||
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
echo "A previously required intermediate Elasticsearch upgrade was detected. Verifying that all Searchnodes/Heavynodes have successfully upgraded Elasticsearch to $es_required_version_statefile_value before proceeding with soup to avoid potential data loss! This command can take up to an hour to complete."
|
||||
timeout --foreground 4000 bash "$es_verification_script" "$es_required_version_statefile_value" "$statefile"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
|
||||
echo "A previous required intermediate Elasticsearch upgrade to $es_required_version_statefile_value has yet to successfully complete across the grid. Please allow time for all Searchnodes/Heavynodes to have upgraded Elasticsearch to $es_required_version_statefile_value before running soup again to avoid potential data loss!"
|
||||
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
|
||||
exit 161
|
||||
fi
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
done
|
||||
|
||||
# if current soup is an intermediate upgrade we can skip the upgrade map check below
|
||||
if [[ $is_active_intermediate_upgrade -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ " ${es_upgrade_map[$es_version]} " =~ " $target_es_version " || "$es_version" == "$target_es_version" ]]; then
|
||||
# supported upgrade
|
||||
return 0
|
||||
else
|
||||
compatible_versions=${es_upgrade_map[$es_version]}
|
||||
if [[ -z "$compatible_versions" ]]; then
|
||||
# If current ES version is not explicitly defined in the upgrade map, we know they have an intermediate upgrade to do.
|
||||
# We default to the lowest ES version defined in es_to_so_version as $first_es_required_version
|
||||
local first_es_required_version=$(printf '%s\n' "${!es_to_so_version[@]}" | sort -V | head -n1)
|
||||
next_step_so_version=${es_to_so_version[$first_es_required_version]}
|
||||
required_es_upgrade_version="$first_es_required_version"
|
||||
else
|
||||
next_step_so_version=${es_to_so_version[${compatible_versions##* }]}
|
||||
required_es_upgrade_version="${compatible_versions##* }"
|
||||
fi
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
echo -e "You are currently running Security Onion $INSTALLEDVERSION. You will need to update to version $next_step_so_version before updating to $(cat $UPDATE_DIR/VERSION).\n"
|
||||
|
||||
es_required_version_statefile="${es_required_version_statefile_base}-${required_es_upgrade_version}"
|
||||
echo "$required_es_upgrade_version" > "$es_required_version_statefile"
|
||||
|
||||
# We expect to upgrade to the latest compatiable minor version of ES
|
||||
create_intermediate_upgrade_verification_script "$es_verification_script"
|
||||
|
||||
if [[ $is_airgap -eq 0 ]]; then
|
||||
run_airgap_intermediate_upgrade
|
||||
else
|
||||
if [[ ! -z $ISOLOC ]]; then
|
||||
originally_requested_iso_location="$ISOLOC"
|
||||
fi
|
||||
# Make sure ISOLOC is not set. Network installs that used soup -f would have ISOLOC set.
|
||||
unset ISOLOC
|
||||
|
||||
run_network_intermediate_upgrade
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
run_airgap_intermediate_upgrade() {
|
||||
local originally_requested_so_version=$(cat $UPDATE_DIR/VERSION)
|
||||
# preserve ISOLOC value, so we can try to use it post intermediate upgrade
|
||||
local originally_requested_iso_location="$ISOLOC"
|
||||
|
||||
# make sure a fresh ISO gets mounted
|
||||
unmount_update
|
||||
|
||||
echo "You can download the $next_step_so_version ISO image from https://download.securityonion.net/file/securityonion/securityonion-$next_step_so_version.iso"
|
||||
echo -e "\nIf you have the next ISO / USB ready, enter the path now eg. /dev/sdd, /home/onion/securityonion-$next_step_so_version.iso:"
|
||||
|
||||
while [[ -z "$next_iso_location" ]] || [[ ! -f "$next_iso_location" && ! -b "$next_iso_location" ]]; do
|
||||
# List removable devices if any are present
|
||||
local removable_devices=$(lsblk -no PATH,SIZE,TYPE,MOUNTPOINTS,RM | awk '$NF==1')
|
||||
if [[ -n "$removable_devices" ]]; then
|
||||
echo "PATH SIZE TYPE MOUNTPOINTS RM"
|
||||
echo "$removable_devices"
|
||||
fi
|
||||
|
||||
read -rp "Device/ISO Path (or 'exit' to quit): " next_iso_location
|
||||
if [[ "${next_iso_location,,}" == "exit" ]]; then
|
||||
echo "Exiting soup. Before reattempting to upgrade to $originally_requested_so_version, please first upgrade to $next_step_so_version to ensure Elasticsearch can properly update through the required versions."
|
||||
|
||||
exit 160
|
||||
fi
|
||||
|
||||
if [[ ! -f "$next_iso_location" && ! -b "$next_iso_location" ]]; then
|
||||
echo "$next_iso_location is not a valid file or block device."
|
||||
next_iso_location=""
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Using $next_iso_location for required intermediary upgrade."
|
||||
exec bash <<EOF
|
||||
ISOLOC=$next_iso_location soup -y && \
|
||||
ISOLOC=$next_iso_location soup -y && \
|
||||
|
||||
echo -e "\n##############################################################################################################################\n" && \
|
||||
echo -e "Verifying Elasticsearch was successfully upgraded to $required_es_upgrade_version across the grid. This part can take a while as Searchnodes/Heavynodes sync up with the Manager! \n\nOnce verification completes the next soup will begin automatically. If verification takes longer than 1 hour it will stop waiting and your grid will remain at $next_step_so_version. Allowing for all Searchnodes/Heavynodes to upgrade Elasticsearch to the required version on their own time.\n" && \
|
||||
|
||||
timeout --foreground 4000 bash /tmp/so_intermediate_upgrade_verification.sh $required_es_upgrade_version $es_required_version_statefile && \
|
||||
|
||||
echo -e "\n##############################################################################################################################\n" && \
|
||||
|
||||
# automatically start the next soup if the original ISO isn't using the same block device we just used
|
||||
if [[ -n "$originally_requested_iso_location" ]] && [[ "$originally_requested_iso_location" != "$next_iso_location" ]]; then
|
||||
umount /tmp/soagupdate
|
||||
ISOLOC=$originally_requested_iso_location soup -y && \
|
||||
ISOLOC=$originally_requested_iso_location soup -y
|
||||
else
|
||||
echo "Could not automatically start next soup to $originally_requested_so_version. Soup will now exit here at $(cat /etc/soversion)" && \
|
||||
|
||||
exit 170
|
||||
fi
|
||||
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
EOF
|
||||
}
|
||||
|
||||
run_network_intermediate_upgrade() {
|
||||
# preserve BRANCH value if set originally
|
||||
if [[ -n "$BRANCH" ]]; then
|
||||
local originally_requested_so_branch="$BRANCH"
|
||||
else
|
||||
local originally_requested_so_branch="2.4/main"
|
||||
fi
|
||||
|
||||
echo "Starting automated intermediate upgrade to $next_step_so_version."
|
||||
echo "After completion, the system will automatically attempt to upgrade to the latest version."
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
exec bash << EOF
|
||||
BRANCH=$next_step_so_version soup -y && \
|
||||
BRANCH=$next_step_so_version soup -y && \
|
||||
|
||||
echo -e "\n##############################################################################################################################\n" && \
|
||||
echo -e "Verifying Elasticsearch was successfully upgraded to $required_es_upgrade_version across the grid. This part can take a while as Searchnodes/Heavynodes sync up with the Manager! \n\nOnce verification completes the next soup will begin automatically. If verification takes longer than 1 hour it will stop waiting and your grid will remain at $next_step_so_version. Allowing for all Searchnodes/Heavynodes to upgrade Elasticsearch to the required version on their own time.\n" && \
|
||||
|
||||
timeout --foreground 4000 bash /tmp/so_intermediate_upgrade_verification.sh $required_es_upgrade_version $es_required_version_statefile && \
|
||||
|
||||
echo -e "\n##############################################################################################################################\n" && \
|
||||
if [[ -n "$originally_requested_iso_location" ]]; then
|
||||
# nonairgap soup that used -f originally, runs intermediate upgrade using network + BRANCH, later coming back to the original ISO for the last soup
|
||||
ISOLOC=$originally_requested_iso_location soup -y && \
|
||||
ISOLOC=$originally_requested_iso_location soup -y
|
||||
else
|
||||
BRANCH=$originally_requested_so_branch soup -y && \
|
||||
BRANCH=$originally_requested_so_branch soup -y
|
||||
fi
|
||||
echo -e "\n##############################################################################################################################\n"
|
||||
EOF
|
||||
}
|
||||
|
||||
create_intermediate_upgrade_verification_script() {
|
||||
# After an intermediate upgrade, verify that ALL nodes running Elasticsearch are at the expected version BEFORE proceeding to the next upgrade step. This is a CRITICAL step
|
||||
local verification_script="$1"
|
||||
|
||||
cat << 'EOF' > "$verification_script"
|
||||
#!/bin/bash
|
||||
|
||||
SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE="/root/so_intermediate_upgrade_verification_failures.log"
|
||||
CURRENT_TIME=$(date +%Y%m%d.%H%M%S)
|
||||
EXPECTED_ES_VERSION="$1"
|
||||
|
||||
if [[ -z "$EXPECTED_ES_VERSION" ]]; then
|
||||
echo -e "\nExpected Elasticsearch version not provided. Usage: $0 <expected_es_version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" ]]; then
|
||||
mv "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE.$CURRENT_TIME"
|
||||
fi
|
||||
|
||||
check_heavynodes_es_version() {
|
||||
# Check if heavynodes are in this grid
|
||||
if ! salt-key -l accepted | grep -q 'heavynode$'; then
|
||||
|
||||
# No heavynodes, skip version check
|
||||
echo "No heavynodes detected in this Security Onion deployment. Skipping heavynode Elasticsearch version verification."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "\nOne or more heavynodes detected. Verifying their Elasticsearch versions."
|
||||
|
||||
local retries=20
|
||||
local retry_count=0
|
||||
local delay=180
|
||||
|
||||
while [[ $retry_count -lt $retries ]]; do
|
||||
# keep stderr with variable for logging
|
||||
heavynode_versions=$(salt -C 'G@role:so-heavynode' cmd.run 'so-elasticsearch-query / --retry 3 --retry-delay 10 | jq ".version.number"' shell=/bin/bash --out=json 2> /dev/null)
|
||||
local exit_status=$?
|
||||
|
||||
# Check that all heavynodes returned good data
|
||||
if [[ $exit_status -ne 0 ]]; then
|
||||
echo "Failed to retrieve Elasticsearch version from one or more heavynodes... Retrying in $delay seconds. Attempt $((retry_count + 1)) of $retries."
|
||||
((retry_count++))
|
||||
sleep $delay
|
||||
|
||||
continue
|
||||
else
|
||||
if echo "$heavynode_versions" | jq -s --arg expected "\"$EXPECTED_ES_VERSION\"" --exit-status 'all(.[]; . | to_entries | all(.[]; .value == $expected))' > /dev/null; then
|
||||
echo -e "\nAll heavynodes are at the expected Elasticsearch version $EXPECTED_ES_VERSION."
|
||||
|
||||
return 0
|
||||
else
|
||||
echo "One or more heavynodes are not at the expected Elasticsearch version $EXPECTED_ES_VERSION. Rechecking in $delay seconds. Attempt $((retry_count + 1)) of $retries."
|
||||
((retry_count++))
|
||||
sleep $delay
|
||||
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
echo "One or more heavynodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION."
|
||||
echo "Current versions:"
|
||||
echo "$heavynode_versions" | jq -s 'add'
|
||||
echo "$heavynode_versions" | jq -s 'add' >> "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE"
|
||||
echo -e "\n Stopping automatic upgrade to latest Security Onion version. Heavynodes must ALL be at Elasticsearch version $EXPECTED_ES_VERSION before proceeding with the next upgrade step to avoid potential data loss!"
|
||||
echo -e "\n Heavynodes will upgrade themselves to Elasticsearch $EXPECTED_ES_VERSION on their own, but this process can take a long time depending on network link between Manager and Heavynodes."
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
check_searchnodes_es_version() {
|
||||
local retries=20
|
||||
local retry_count=0
|
||||
local delay=180
|
||||
|
||||
while [[ $retry_count -lt $retries ]]; do
|
||||
# keep stderr with variable for logging
|
||||
cluster_versions=$(so-elasticsearch-query _nodes/_all/version --retry 5 --retry-delay 10 --fail 2>&1)
|
||||
local exit_status=$?
|
||||
|
||||
if [[ $exit_status -ne 0 ]]; then
|
||||
echo "Failed to retrieve Elasticsearch versions from searchnodes... Retrying in $delay seconds. Attempt $((retry_count + 1)) of $retries."
|
||||
((retry_count++))
|
||||
sleep $delay
|
||||
|
||||
continue
|
||||
else
|
||||
if echo "$cluster_versions" | jq --arg expected "$EXPECTED_ES_VERSION" --exit-status '.nodes | to_entries | all(.[].value.version; . == $expected)' > /dev/null; then
|
||||
echo "All Searchnodes are at the expected Elasticsearch version $EXPECTED_ES_VERSION."
|
||||
|
||||
return 0
|
||||
else
|
||||
echo "One or more Searchnodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION. Rechecking in $delay seconds. Attempt $((retry_count + 1)) of $retries."
|
||||
((retry_count++))
|
||||
sleep $delay
|
||||
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
echo "One or more Searchnodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION."
|
||||
echo "Current versions:"
|
||||
echo "$cluster_versions" | jq '.nodes | to_entries | map({(.value.name): .value.version}) | sort | add'
|
||||
echo "$cluster_versions" >> "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE"
|
||||
echo -e "\nStopping automatic upgrade to latest version. Searchnodes must ALL be at Elasticsearch version $EXPECTED_ES_VERSION before proceeding with the next upgrade step to avoid potential data loss!"
|
||||
echo -e "\nSearchnodes will upgrade themselves to Elasticsearch $EXPECTED_ES_VERSION on their own, but this process can take a while depending on cluster size / network link between Manager and Searchnodes."
|
||||
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
|
||||
echo "$cluster_versions" > "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE"
|
||||
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
# Need to add a check for heavynodes and ensure all heavynodes get their own "cluster" upgraded before moving on to final upgrade.
|
||||
check_searchnodes_es_version || exit 1
|
||||
check_heavynodes_es_version || exit 1
|
||||
|
||||
# Remove required version state file after successful verification
|
||||
rm -f "$2"
|
||||
|
||||
exit 0
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Keeping this block in case we need to do a hotfix that requires salt update
|
||||
apply_hotfix() {
|
||||
if [[ "$INSTALLEDVERSION" == "2.4.20" ]] ; then
|
||||
@@ -1630,7 +2060,7 @@ apply_hotfix() {
|
||||
mv /etc/pki/managerssl.crt /etc/pki/managerssl.crt.old
|
||||
mv /etc/pki/managerssl.key /etc/pki/managerssl.key.old
|
||||
systemctl_func "start" "salt-minion"
|
||||
(wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
(wait_for_salt_minion "$MINIONID" "120" "4" "$SOUP_LOG" || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
fi
|
||||
else
|
||||
echo "No actions required. ($INSTALLEDVERSION/$HOTFIXVERSION)"
|
||||
@@ -1700,6 +2130,9 @@ main() {
|
||||
echo "Verifying we have the latest soup script."
|
||||
verify_latest_update_script
|
||||
|
||||
echo "Verifying Elasticsearch version compatibility before upgrading."
|
||||
verify_es_version_compatibility
|
||||
|
||||
echo "Let's see if we need to update Security Onion."
|
||||
upgrade_check
|
||||
upgrade_space
|
||||
@@ -1827,7 +2260,7 @@ main() {
|
||||
echo ""
|
||||
echo "Running a highstate. This could take several minutes."
|
||||
set +e
|
||||
(wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
(wait_for_salt_minion "$MINIONID" "120" "4" "$SOUP_LOG" || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
highstate
|
||||
set -e
|
||||
|
||||
@@ -1840,7 +2273,7 @@ main() {
|
||||
check_saltmaster_status
|
||||
|
||||
echo "Running a highstate to complete the Security Onion upgrade on this manager. This could take several minutes."
|
||||
(wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
(wait_for_salt_minion "$MINIONID" "120" "4" "$SOUP_LOG" || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG"
|
||||
|
||||
# Stop long-running scripts to allow potentially updated scripts to load on the next execution.
|
||||
killall salt-relay.sh
|
||||
@@ -1865,7 +2298,7 @@ main() {
|
||||
if [[ $is_airgap -eq 0 ]]; then
|
||||
echo ""
|
||||
echo "Cleaning repos on remote Security Onion nodes."
|
||||
salt -C 'not *_eval and not *_manager and not *_managersearch and not *_standalone and G@os:CentOS' cmd.run "yum clean all"
|
||||
salt -C 'not *_eval and not *_manager* and not *_standalone and G@os:OEL' cmd.run "dnf clean all"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||
{% if sls.split('.')[0] in allowed_states %}
|
||||
|
||||
include:
|
||||
- ssl
|
||||
|
||||
# Drop the correct nginx config based on role
|
||||
nginxconfdir:
|
||||
file.directory:
|
||||
|
||||
@@ -8,81 +8,14 @@
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
||||
{% from 'nginx/map.jinja' import NGINXMERGED %}
|
||||
{% set ca_server = GLOBALS.minion_id %}
|
||||
|
||||
include:
|
||||
- nginx.ssl
|
||||
- nginx.config
|
||||
- nginx.sostatus
|
||||
|
||||
|
||||
{% if grains.role not in ['so-fleet'] %}
|
||||
|
||||
{# if the user has selected to replace the crt and key in the ui #}
|
||||
{% if NGINXMERGED.ssl.replace_cert %}
|
||||
|
||||
managerssl_key:
|
||||
file.managed:
|
||||
- name: /etc/pki/managerssl.key
|
||||
- source: salt://nginx/ssl/ssl.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
managerssl_crt:
|
||||
file.managed:
|
||||
- name: /etc/pki/managerssl.crt
|
||||
- source: salt://nginx/ssl/ssl.crt
|
||||
- mode: 644
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
{% else %}
|
||||
|
||||
managerssl_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/managerssl.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/managerssl.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/managerssl.crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
# Create a cert for the reverse proxy
|
||||
managerssl_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/managerssl.crt
|
||||
- ca_server: {{ ca_server }}
|
||||
- signing_policy: managerssl
|
||||
- private_key: /etc/pki/managerssl.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: "DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}, DNS:{{ GLOBALS.url_base }}"
|
||||
- days_remaining: 0
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
{% endif %}
|
||||
|
||||
msslkeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/managerssl.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
{% if GLOBALS.role != 'so-fleet' %}
|
||||
{% set container_config = 'so-nginx' %}
|
||||
make-rule-dir-nginx:
|
||||
file.directory:
|
||||
- name: /nsm/rules
|
||||
@@ -92,15 +25,11 @@ make-rule-dir-nginx:
|
||||
- user
|
||||
- group
|
||||
- show_changes: False
|
||||
|
||||
{% endif %}
|
||||
|
||||
{# if this is an so-fleet node then we want to use the port bindings, custom bind mounts defined for fleet #}
|
||||
{% if GLOBALS.role == 'so-fleet' %}
|
||||
{% set container_config = 'so-nginx-fleet-node' %}
|
||||
{% else %}
|
||||
{% set container_config = 'so-nginx' %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# if this is an so-fleet node then we want to use the port bindings, custom bind mounts defined for fleet #}
|
||||
{% set container_config = 'so-nginx-fleet-node' %}
|
||||
{% endif %}
|
||||
|
||||
so-nginx:
|
||||
docker_container.running:
|
||||
@@ -154,18 +83,27 @@ so-nginx:
|
||||
- watch:
|
||||
- file: nginxconf
|
||||
- file: nginxconfdir
|
||||
- require:
|
||||
- file: nginxconf
|
||||
{% if GLOBALS.is_manager %}
|
||||
{% if NGINXMERGED.ssl.replace_cert %}
|
||||
{% if GLOBALS.is_manager %}
|
||||
{% if NGINXMERGED.ssl.replace_cert %}
|
||||
- file: managerssl_key
|
||||
- file: managerssl_crt
|
||||
{% else %}
|
||||
{% else %}
|
||||
- x509: managerssl_key
|
||||
- x509: managerssl_crt
|
||||
{% endif%}
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
- require:
|
||||
- file: nginxconf
|
||||
{% if GLOBALS.is_manager %}
|
||||
{% if NGINXMERGED.ssl.replace_cert %}
|
||||
- file: managerssl_key
|
||||
- file: managerssl_crt
|
||||
{% else %}
|
||||
- x509: managerssl_key
|
||||
- x509: managerssl_crt
|
||||
{% endif%}
|
||||
- file: navigatorconfig
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
delete_so-nginx_so-status.disabled:
|
||||
file.uncomment:
|
||||
|
||||
87
salt/nginx/ssl.sls
Normal file
87
salt/nginx/ssl.sls
Normal file
@@ -0,0 +1,87 @@
|
||||
# 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 'nginx/map.jinja' import NGINXMERGED %}
|
||||
{% from 'ca/map.jinja' import CA %}
|
||||
|
||||
{% if GLOBALS.role != 'so-fleet' %}
|
||||
{# if the user has selected to replace the crt and key in the ui #}
|
||||
{% if NGINXMERGED.ssl.replace_cert %}
|
||||
|
||||
managerssl_key:
|
||||
file.managed:
|
||||
- name: /etc/pki/managerssl.key
|
||||
- source: salt://nginx/ssl/ssl.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
managerssl_crt:
|
||||
file.managed:
|
||||
- name: /etc/pki/managerssl.crt
|
||||
- source: salt://nginx/ssl/ssl.crt
|
||||
- mode: 644
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
{% else %}
|
||||
|
||||
managerssl_key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/pki/managerssl.key
|
||||
- keysize: 4096
|
||||
- backup: True
|
||||
- new: True
|
||||
{% if salt['file.file_exists']('/etc/pki/managerssl.key') -%}
|
||||
- prereq:
|
||||
- x509: /etc/pki/managerssl.crt
|
||||
{%- endif %}
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
# Create a cert for the reverse proxy
|
||||
managerssl_crt:
|
||||
x509.certificate_managed:
|
||||
- name: /etc/pki/managerssl.crt
|
||||
- ca_server: {{ CA.server }}
|
||||
- signing_policy: managerssl
|
||||
- private_key: /etc/pki/managerssl.key
|
||||
- CN: {{ GLOBALS.hostname }}
|
||||
- subjectAltName: "DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}, DNS:{{ GLOBALS.url_base }}"
|
||||
- days_remaining: 7
|
||||
- days_valid: 820
|
||||
- backup: True
|
||||
- timeout: 30
|
||||
- retry:
|
||||
attempts: 5
|
||||
interval: 30
|
||||
- watch_in:
|
||||
- docker_container: so-nginx
|
||||
|
||||
{% endif %}
|
||||
|
||||
msslkeyperms:
|
||||
file.managed:
|
||||
- replace: False
|
||||
- name: /etc/pki/managerssl.key
|
||||
- mode: 640
|
||||
- group: 939
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
22
salt/pcap/ca.sls
Normal file
22
salt/pcap/ca.sls
Normal file
@@ -0,0 +1,22 @@
|
||||
# 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 or sls in allowed_states%}
|
||||
|
||||
stenoca:
|
||||
file.directory:
|
||||
- name: /opt/so/conf/steno/certs
|
||||
- user: 941
|
||||
- group: 939
|
||||
- makedirs: True
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -57,12 +57,6 @@ stenoconf:
|
||||
PCAPMERGED: {{ PCAPMERGED }}
|
||||
STENO_BPF_COMPILED: "{{ STENO_BPF_COMPILED }}"
|
||||
|
||||
stenoca:
|
||||
file.directory:
|
||||
- name: /opt/so/conf/steno/certs
|
||||
- user: 941
|
||||
- group: 939
|
||||
|
||||
pcaptmpdir:
|
||||
file.directory:
|
||||
- name: /nsm/pcaptmp
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user