mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-06 17:22:49 +01:00
Compare commits
1683 Commits
2.3.51
...
feature/us
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c702e269 | ||
|
|
d3f25f8d74 | ||
|
|
8bd4ba3acd | ||
|
|
e5927d0bf7 | ||
|
|
9dd89f6be7 | ||
|
|
796eb59dc6 | ||
|
|
55fed43469 | ||
|
|
af83019427 | ||
|
|
4149236cda | ||
|
|
825106d074 | ||
|
|
1a3324868a | ||
|
|
bc87bb4770 | ||
|
|
6aae48bdae | ||
|
|
a0425a48e6 | ||
|
|
4b89bf7bbc | ||
|
|
5fc5afa9ea | ||
|
|
ddec8e4da0 | ||
|
|
9c0e8cedba | ||
|
|
5054da0027 | ||
|
|
96f1f0174b | ||
|
|
cd1f0c0440 | ||
|
|
12546a8efa | ||
|
|
3f5956b56d | ||
|
|
6e49ab0558 | ||
|
|
c52df32f05 | ||
|
|
c0602f4222 | ||
|
|
d4b412bcbe | ||
|
|
66e2de0934 | ||
|
|
c93794a402 | ||
|
|
98efc6f2ed | ||
|
|
59ef734064 | ||
|
|
922657afbc | ||
|
|
5f3601ac78 | ||
|
|
2fe4fa06a6 | ||
|
|
773c580e77 | ||
|
|
aca684d55a | ||
|
|
6f391dbe50 | ||
|
|
8d033264e7 | ||
|
|
262d2023b5 | ||
|
|
d143a309a1 | ||
|
|
ac400f1c41 | ||
|
|
df495c0017 | ||
|
|
8c454973ad | ||
|
|
a16e6aca22 | ||
|
|
ce21ae11f5 | ||
|
|
fdd9706669 | ||
|
|
8fa9a180b2 | ||
|
|
6288365a50 | ||
|
|
5448107310 | ||
|
|
adaf3faf90 | ||
|
|
1bd8e226b4 | ||
|
|
f60f0b5b6d | ||
|
|
adc867846c | ||
|
|
5945326817 | ||
|
|
90cbb5d00e | ||
|
|
8bb2789c6f | ||
|
|
11fc0da971 | ||
|
|
76a1d767f2 | ||
|
|
a2152446ea | ||
|
|
d4d9032bfc | ||
|
|
4e3f43bee4 | ||
|
|
57377e0a0e | ||
|
|
2514d36ccd | ||
|
|
809dbc0a48 | ||
|
|
b51405d5e8 | ||
|
|
d1cfc4a8dc | ||
|
|
731bbabe4c | ||
|
|
d4509ff4d8 | ||
|
|
85c0b0818b | ||
|
|
f674555290 | ||
|
|
a8aae544d5 | ||
|
|
6f9db25ea7 | ||
|
|
405e78858a | ||
|
|
146e1f4297 | ||
|
|
f78e0fb7b9 | ||
|
|
6e6d2d1949 | ||
|
|
ca5d20fecb | ||
|
|
dcfaece8b1 | ||
|
|
af0e062193 | ||
|
|
56acedfbf7 | ||
|
|
4b0a5c3a17 | ||
|
|
052192e1d6 | ||
|
|
92131d4bb7 | ||
|
|
9ac1cb0e76 | ||
|
|
ffbb04bb5a | ||
|
|
cc1dea446c | ||
|
|
7f3379e034 | ||
|
|
8c46a2d1db | ||
|
|
ba621639bd | ||
|
|
2fb9196604 | ||
|
|
48c71c8b12 | ||
|
|
8d185ced61 | ||
|
|
9141c271f0 | ||
|
|
bc2e470da9 | ||
|
|
0f817cd735 | ||
|
|
df5901a65d | ||
|
|
3cd1b5687e | ||
|
|
86a42addf0 | ||
|
|
6bf4d5a576 | ||
|
|
efa5eb9f7f | ||
|
|
22959f0260 | ||
|
|
8da2133cff | ||
|
|
1472af4fc3 | ||
|
|
f91a6d3cb6 | ||
|
|
96f427d924 | ||
|
|
184356618c | ||
|
|
ed3b2e4569 | ||
|
|
62b41af069 | ||
|
|
569cb24861 | ||
|
|
ac22df8381 | ||
|
|
446d6bd532 | ||
|
|
fcf889be2f | ||
|
|
8168f19b31 | ||
|
|
ba553d971c | ||
|
|
9137454a25 | ||
|
|
7ebd861e32 | ||
|
|
d110b63050 | ||
|
|
3806f10f8b | ||
|
|
83bd314a63 | ||
|
|
6cd7b252df | ||
|
|
dea03bbf5e | ||
|
|
9edc543262 | ||
|
|
d3dc5ffc5a | ||
|
|
2c296e832f | ||
|
|
b350174df1 | ||
|
|
67ebfeab16 | ||
|
|
435f430747 | ||
|
|
aa9e1701f0 | ||
|
|
02d9b87f66 | ||
|
|
cfd46c1e58 | ||
|
|
392305e4ed | ||
|
|
5ff14ab652 | ||
|
|
1890c7244a | ||
|
|
a8c4ed7bbf | ||
|
|
91f54537d7 | ||
|
|
7e3a4656aa | ||
|
|
8a04fcd919 | ||
|
|
409ab623a5 | ||
|
|
ac85d1598e | ||
|
|
4c8e68e014 | ||
|
|
57c6e26634 | ||
|
|
b6a1d7418e | ||
|
|
6eb1a0b0ae | ||
|
|
9301b8f5b9 | ||
|
|
202977a323 | ||
|
|
9597373e4a | ||
|
|
f80b70e008 | ||
|
|
04d2b52306 | ||
|
|
af7830c2be | ||
|
|
3c3cb47b88 | ||
|
|
da4e92a7a3 | ||
|
|
3afb0bd263 | ||
|
|
f6e6b20392 | ||
|
|
3835a4401e | ||
|
|
4bae57d994 | ||
|
|
ea7289d92e | ||
|
|
48eaf190e9 | ||
|
|
497de0fede | ||
|
|
70e3bc7eb8 | ||
|
|
eefc9cfcb6 | ||
|
|
42b8955883 | ||
|
|
f6b753b805 | ||
|
|
17fc03a553 | ||
|
|
8bf88043ac | ||
|
|
79640342f2 | ||
|
|
3ad47742bd | ||
|
|
a8c02252dc | ||
|
|
fbef420155 | ||
|
|
ccd84e441d | ||
|
|
46d3eb452d | ||
|
|
083d467aa9 | ||
|
|
f026ac1b41 | ||
|
|
9ea292b11e | ||
|
|
e2ee460fdd | ||
|
|
5b70ff61d1 | ||
|
|
3b2ca89852 | ||
|
|
199c97684c | ||
|
|
d67e34dac4 | ||
|
|
49a573074e | ||
|
|
6c16d6d222 | ||
|
|
acba82d194 | ||
|
|
f66d915f5d | ||
|
|
ee2dd75dfd | ||
|
|
50b7779d6e | ||
|
|
ad71485361 | ||
|
|
8b2cccdf4a | ||
|
|
dbe4a7de63 | ||
|
|
9c4bba9ac9 | ||
|
|
b3fd7c548c | ||
|
|
dcf6dfb676 | ||
|
|
246d41c552 | ||
|
|
988932293f | ||
|
|
0b28e89f3c | ||
|
|
665732bd32 | ||
|
|
b599b49630 | ||
|
|
edb3b602a9 | ||
|
|
a4289b7ab9 | ||
|
|
9b0ce8b395 | ||
|
|
05456b38d1 | ||
|
|
4fc58e7a5a | ||
|
|
dc07aba63d | ||
|
|
f1d66e2d51 | ||
|
|
fab0dd2bad | ||
|
|
747f14d60e | ||
|
|
fb35ff40b4 | ||
|
|
2cb31a4c05 | ||
|
|
32f986c505 | ||
|
|
c8ee67f354 | ||
|
|
db80315c06 | ||
|
|
8e3b08a831 | ||
|
|
677f62ebd1 | ||
|
|
d927e79154 | ||
|
|
8670aa6cd8 | ||
|
|
7c7c225a41 | ||
|
|
54b034b537 | ||
|
|
2232759fa4 | ||
|
|
f65eea6a03 | ||
|
|
e4a77acfe6 | ||
|
|
9671dab2a3 | ||
|
|
e6adb46364 | ||
|
|
7abb2e5935 | ||
|
|
561f86eac8 | ||
|
|
9a9d1480de | ||
|
|
8b52f87a60 | ||
|
|
a6f399acf4 | ||
|
|
3534256517 | ||
|
|
b109d95d6f | ||
|
|
b756c0cd38 | ||
|
|
3517ea3f2a | ||
|
|
5d414c8bdd | ||
|
|
2b56b53c15 | ||
|
|
2ba619144c | ||
|
|
a9be0a0409 | ||
|
|
bf116d210e | ||
|
|
f8b62b63f9 | ||
|
|
f4d9455872 | ||
|
|
936c796b9d | ||
|
|
8ff122262c | ||
|
|
c4a1fbd82a | ||
|
|
8857fca797 | ||
|
|
b63b50d98c | ||
|
|
c17187708e | ||
|
|
095e6bd48c | ||
|
|
c4b9244f9a | ||
|
|
2ba548fcfc | ||
|
|
f76a52b2ee | ||
|
|
b555ad16da | ||
|
|
b1c67f696e | ||
|
|
d08149f728 | ||
|
|
a5cba5ecf8 | ||
|
|
f081938be5 | ||
|
|
c2b18efdbb | ||
|
|
6b480a5ba4 | ||
|
|
d6eeb0b735 | ||
|
|
3000c57428 | ||
|
|
5c5b4004e9 | ||
|
|
05e0f92ec5 | ||
|
|
0cea5e8f22 | ||
|
|
7eb42fa6bd | ||
|
|
18ce9c7819 | ||
|
|
b3e5319806 | ||
|
|
c8c8cf203f | ||
|
|
19056b9177 | ||
|
|
75490a2536 | ||
|
|
eee612e73d | ||
|
|
9e9079f9cb | ||
|
|
331801eec2 | ||
|
|
a0216cea57 | ||
|
|
e7f43cff5e | ||
|
|
90d473f2d6 | ||
|
|
bf403a8307 | ||
|
|
58d62f29ea | ||
|
|
bcf03773c0 | ||
|
|
c0dd9efd9b | ||
|
|
36ae07b78e | ||
|
|
d77328608e | ||
|
|
682cbfd223 | ||
|
|
fa2edb2b59 | ||
|
|
0c679b62b2 | ||
|
|
7e8d74e770 | ||
|
|
9a78d13bee | ||
|
|
c469d12a49 | ||
|
|
d5f42e0d7c | ||
|
|
926551d398 | ||
|
|
3be0d05eea | ||
|
|
7fa43a276a | ||
|
|
2bfedbd581 | ||
|
|
dca30146ab | ||
|
|
6e34905b42 | ||
|
|
ee7e714f43 | ||
|
|
d7e5377a44 | ||
|
|
38b16a507b | ||
|
|
17af513692 | ||
|
|
283f7296bc | ||
|
|
9f6407fcb0 | ||
|
|
f61400680d | ||
|
|
fed8bfac67 | ||
|
|
62971d8c15 | ||
|
|
352e30f9e1 | ||
|
|
451b19dc4d | ||
|
|
d5d970672d | ||
|
|
f93c6146f5 | ||
|
|
40dd33affe | ||
|
|
f374dcbb58 | ||
|
|
77ee1db44c | ||
|
|
8784d65023 | ||
|
|
15fe7512b7 | ||
|
|
0beeeb94bf | ||
|
|
928aed27c5 | ||
|
|
387d4d6ad5 | ||
|
|
adf6cb4b3c | ||
|
|
0ed2ce0766 | ||
|
|
b5cb47e066 | ||
|
|
8061508330 | ||
|
|
adffb11800 | ||
|
|
8619af59cc | ||
|
|
7ecfb55b70 | ||
|
|
b496810b63 | ||
|
|
e1ad02c28d | ||
|
|
2f8bb5a2a6 | ||
|
|
6f3e441bf7 | ||
|
|
7f1585dcc0 | ||
|
|
9453ed7fa1 | ||
|
|
64f25961b0 | ||
|
|
b9a3d3a6a9 | ||
|
|
36cb0d6c42 | ||
|
|
1b2268dfe5 | ||
|
|
00e5b54dda | ||
|
|
4016b416ec | ||
|
|
7590728a0b | ||
|
|
bb36fc1ed8 | ||
|
|
d0a6dafc8b | ||
|
|
76097476d3 | ||
|
|
8b3b0bf160 | ||
|
|
f19680b3e6 | ||
|
|
7e1bbe3cc2 | ||
|
|
947285e932 | ||
|
|
1741f5068a | ||
|
|
a9f6c84d7c | ||
|
|
59852841ff | ||
|
|
6f1f7d2a63 | ||
|
|
8de8d58155 | ||
|
|
8feeff97b5 | ||
|
|
032373187c | ||
|
|
db2b70f655 | ||
|
|
1800ec4570 | ||
|
|
8a5960c220 | ||
|
|
9797a15218 | ||
|
|
c7b15a9b1f | ||
|
|
cba97802fe | ||
|
|
025256aeaf | ||
|
|
490f7eaf81 | ||
|
|
6a2bf11a75 | ||
|
|
78d30285b1 | ||
|
|
f1fafa015e | ||
|
|
6cdc214582 | ||
|
|
15049f44b9 | ||
|
|
42a642b85c | ||
|
|
3b45e68ead | ||
|
|
5ee0ea3fe7 | ||
|
|
55c60f485c | ||
|
|
78e88e0765 | ||
|
|
a9b250c0f4 | ||
|
|
ae9753326a | ||
|
|
c8fb504ee0 | ||
|
|
54eec92621 | ||
|
|
7832e59629 | ||
|
|
f9001654bb | ||
|
|
2a504a061b | ||
|
|
bb9c6446e4 | ||
|
|
e7581036f7 | ||
|
|
e1629d7ec4 | ||
|
|
b4873bd296 | ||
|
|
3044edb104 | ||
|
|
a495779552 | ||
|
|
880c1b97b0 | ||
|
|
7a4fa8879c | ||
|
|
adb8292814 | ||
|
|
6e7a5fa326 | ||
|
|
23ea53248d | ||
|
|
f1a5991699 | ||
|
|
c69ad091f7 | ||
|
|
b97361fab9 | ||
|
|
36e1795295 | ||
|
|
498e385484 | ||
|
|
af687b0706 | ||
|
|
19489f3626 | ||
|
|
89d1df8a1d | ||
|
|
946cf81a27 | ||
|
|
2561480371 | ||
|
|
d21dee162d | ||
|
|
444d067112 | ||
|
|
2a82373051 | ||
|
|
64758a534c | ||
|
|
7517a63008 | ||
|
|
b2facdf31c | ||
|
|
4c54d6309c | ||
|
|
62c3afc81d | ||
|
|
7d8c8144b0 | ||
|
|
a2c4fce1ef | ||
|
|
599aba43d9 | ||
|
|
fa4f92cdda | ||
|
|
5d98c0d14c | ||
|
|
27614569e3 | ||
|
|
ec357cca3c | ||
|
|
26681ac98a | ||
|
|
748f0f2a1d | ||
|
|
869af548af | ||
|
|
2fd344822d | ||
|
|
a3e0fb127a | ||
|
|
9569e73bd0 | ||
|
|
96d783b158 | ||
|
|
e0c097c270 | ||
|
|
e6fce4cf3e | ||
|
|
6ef9a5c95d | ||
|
|
727613b6e1 | ||
|
|
5013aa8490 | ||
|
|
72a1b299ac | ||
|
|
cfaa0e679c | ||
|
|
4ddf2b49ce | ||
|
|
bb95963d73 | ||
|
|
dfa9afde0e | ||
|
|
fa2333b9ef | ||
|
|
8b9c43915d | ||
|
|
36832139b2 | ||
|
|
c3bf835566 | ||
|
|
39d3c7c6ed | ||
|
|
b1a5527e82 | ||
|
|
d0592c4293 | ||
|
|
b1d0e3e93f | ||
|
|
b069377c8a | ||
|
|
e9a44c6e1b | ||
|
|
275163f85d | ||
|
|
98f74c25ba | ||
|
|
3064800820 | ||
|
|
f8bea82430 | ||
|
|
8b905b585d | ||
|
|
b44358fc26 | ||
|
|
8a9dcb7fdb | ||
|
|
a01d49981c | ||
|
|
b8b1867e52 | ||
|
|
292ce37ce4 | ||
|
|
73dacdcbff | ||
|
|
bea7555464 | ||
|
|
52c1298b9b | ||
|
|
cdb9dcbaec | ||
|
|
37153288e8 | ||
|
|
edf75255cf | ||
|
|
9eb6f5942e | ||
|
|
dae41d279a | ||
|
|
07288367cf | ||
|
|
f4186feffa | ||
|
|
d82e91f69e | ||
|
|
a2680fad0a | ||
|
|
5c2be487f5 | ||
|
|
531c9de488 | ||
|
|
19efa493ad | ||
|
|
0db3f14261 | ||
|
|
ed28e4d000 | ||
|
|
2c8cbf0db1 | ||
|
|
c1537335b1 | ||
|
|
5f475ff9cb | ||
|
|
481ffb1cda | ||
|
|
50b78681f2 | ||
|
|
3924b8f5db | ||
|
|
a9049eccd4 | ||
|
|
1a7237bcdf | ||
|
|
1e5e1c9ef0 | ||
|
|
47cd1ddc0a | ||
|
|
aed73511e4 | ||
|
|
a3f62c81c3 | ||
|
|
730503b69c | ||
|
|
3508f3d8c1 | ||
|
|
5704906b11 | ||
|
|
357c1db445 | ||
|
|
5377a1a85e | ||
|
|
7f2d7eb038 | ||
|
|
30e781d076 | ||
|
|
01323cc192 | ||
|
|
109c83d8c3 | ||
|
|
e864bc5404 | ||
|
|
22eb82e950 | ||
|
|
b877aa44bc | ||
|
|
4d307c53e8 | ||
|
|
d0c87cd317 | ||
|
|
0d074dafd4 | ||
|
|
5b77dc109f | ||
|
|
3ce48acadd | ||
|
|
fbd9bab2f1 | ||
|
|
5526a2bc3a | ||
|
|
18d81352c6 | ||
|
|
889d235c45 | ||
|
|
3fc26312e0 | ||
|
|
b81d38e392 | ||
|
|
82da0041a4 | ||
|
|
782b01e76f | ||
|
|
3bf9685df8 | ||
|
|
4cf91f6c86 | ||
|
|
a43b37f234 | ||
|
|
e0dc62b6e9 | ||
|
|
c213834316 | ||
|
|
c06668c68e | ||
|
|
a75238bc3f | ||
|
|
ac417867ed | ||
|
|
1614b70853 | ||
|
|
0882158e03 | ||
|
|
1a03853a7c | ||
|
|
aff571faf2 | ||
|
|
e0faa4c75b | ||
|
|
e3e2e1d851 | ||
|
|
2affaf07a2 | ||
|
|
39e5ded58d | ||
|
|
4d41d3aee1 | ||
|
|
5c8067728e | ||
|
|
1d905124d3 | ||
|
|
e0a289182f | ||
|
|
551dba955c | ||
|
|
9970e54081 | ||
|
|
ff989b1c73 | ||
|
|
2ffb723bbd | ||
|
|
6ae2fba71f | ||
|
|
2cc25587d9 | ||
|
|
614a6dc9fe | ||
|
|
4b7667d87f | ||
|
|
74b0b365bd | ||
|
|
0b0d508585 | ||
|
|
0534a2dda3 | ||
|
|
f8ab0ac8a9 | ||
|
|
0ae09cc630 | ||
|
|
332c4dda22 | ||
|
|
679faddd52 | ||
|
|
0b42b19763 | ||
|
|
943bd3e902 | ||
|
|
4af6a901a1 | ||
|
|
9c310de459 | ||
|
|
4f6a3269cb | ||
|
|
6a2e1df7d4 | ||
|
|
db50ef71b4 | ||
|
|
4e2d5018a2 | ||
|
|
94688a9adb | ||
|
|
63f67b3500 | ||
|
|
eaa5e41651 | ||
|
|
c83f119cc0 | ||
|
|
5d235e932c | ||
|
|
93f2cd75a4 | ||
|
|
f06ab8b77d | ||
|
|
03b45512fa | ||
|
|
b8600be0f1 | ||
|
|
19a02baa7c | ||
|
|
3c59579f99 | ||
|
|
3f989590ad | ||
|
|
72cff7ec7a | ||
|
|
e3900606dc | ||
|
|
a2fd8ae200 | ||
|
|
b7591093cf | ||
|
|
51439cd1ab | ||
|
|
94ea1f856b | ||
|
|
fbbb7f4e85 | ||
|
|
7b3a0cd1e4 | ||
|
|
9fb28709d5 | ||
|
|
649f339934 | ||
|
|
f659079542 | ||
|
|
ce70380f0f | ||
|
|
c4d402d8b4 | ||
|
|
9f5dafd560 | ||
|
|
1cee603ee4 | ||
|
|
a14854d56d | ||
|
|
2bf471054b | ||
|
|
56894b9581 | ||
|
|
10126bb7ef | ||
|
|
6dfc943e8c | ||
|
|
84ecc3cba7 | ||
|
|
0ad3d826eb | ||
|
|
d785dafe2f | ||
|
|
e3dffcc2cb | ||
|
|
556bad6925 | ||
|
|
446821e9fd | ||
|
|
576c893eb3 | ||
|
|
34a5d6e56a | ||
|
|
324e6b12e2 | ||
|
|
007b15979a | ||
|
|
c168703e9f | ||
|
|
527a793e94 | ||
|
|
61ebedc0e9 | ||
|
|
e09aa4e5d4 | ||
|
|
e7b04b862f | ||
|
|
62edfd0b7f | ||
|
|
958575c22a | ||
|
|
0c8e11dc9f | ||
|
|
5b9ef3bc0d | ||
|
|
c12f380bc3 | ||
|
|
dc25ed2594 | ||
|
|
9f51f02ab4 | ||
|
|
f6f4375e13 | ||
|
|
ed116cf850 | ||
|
|
476ecccbc1 | ||
|
|
c09cebbd6b | ||
|
|
0ed92fd9bd | ||
|
|
c3454c9e8a | ||
|
|
3425a0fe78 | ||
|
|
9605eda559 | ||
|
|
ff09d9ca58 | ||
|
|
77b82bf2c0 | ||
|
|
ccc8f9ff0a | ||
|
|
43d20226a8 | ||
|
|
4fe0a1d7b4 | ||
|
|
7a48a94624 | ||
|
|
1aacc27cd4 | ||
|
|
92858cd13a | ||
|
|
99cb38362a | ||
|
|
bfd632e20a | ||
|
|
518f9fceb0 | ||
|
|
2b34da0fee | ||
|
|
72859adb13 | ||
|
|
a27263435a | ||
|
|
f8cdf5bca3 | ||
|
|
ca5339341f | ||
|
|
c5d120293d | ||
|
|
12b5c0899b | ||
|
|
09d5097837 | ||
|
|
de5f823abf | ||
|
|
7b93f355e2 | ||
|
|
a27569f20b | ||
|
|
fd1e632386 | ||
|
|
0681d29bb0 | ||
|
|
ef650c6ee6 | ||
|
|
24f36bb4c9 | ||
|
|
9783d13ea3 | ||
|
|
427ec98ce5 | ||
|
|
72ba29fb7b | ||
|
|
2859bff0e4 | ||
|
|
6e921415ea | ||
|
|
2f8b68e67a | ||
|
|
e762491039 | ||
|
|
11381e304b | ||
|
|
6d49bca0ac | ||
|
|
8ea89932ae | ||
|
|
f87cf123b0 | ||
|
|
80f4d03254 | ||
|
|
a9cc68f89e | ||
|
|
b053f29a89 | ||
|
|
19cfce5e0b | ||
|
|
c4a32ca631 | ||
|
|
b78da5c237 | ||
|
|
0abf7593ed | ||
|
|
aa420b914b | ||
|
|
f096b513b7 | ||
|
|
51b517581a | ||
|
|
936c998ecb | ||
|
|
02372d130a | ||
|
|
6f9a263af3 | ||
|
|
43ffaab82c | ||
|
|
dccfdb14e4 | ||
|
|
21f3b3d985 | ||
|
|
e2d74b115f | ||
|
|
13741400f1 | ||
|
|
d0f587858c | ||
|
|
acca8cc5d2 | ||
|
|
ef950955bd | ||
|
|
9a8ccef828 | ||
|
|
7b8e23fadd | ||
|
|
18335afa7f | ||
|
|
41e8be87b6 | ||
|
|
39f32a6e13 | ||
|
|
8e9f95652d | ||
|
|
30489e4117 | ||
|
|
9dc9f10003 | ||
|
|
1ced05c1d2 | ||
|
|
41b246b8b3 | ||
|
|
a12f19c533 | ||
|
|
f1c91555ae | ||
|
|
e39de8c7bc | ||
|
|
d0e312ec42 | ||
|
|
e492833453 | ||
|
|
9beacacd44 | ||
|
|
aad14b2461 | ||
|
|
4955b552df | ||
|
|
55e8a777d4 | ||
|
|
a98ed282c0 | ||
|
|
7504b1cb2e | ||
|
|
afab1cb1e6 | ||
|
|
cd0b9bbe4a | ||
|
|
3ea29e77a9 | ||
|
|
fb4c2c35e3 | ||
|
|
81ccce8659 | ||
|
|
0d5e3771f5 | ||
|
|
2030ef65f1 | ||
|
|
b6c361f83d | ||
|
|
9404cb635d | ||
|
|
da53b39c15 | ||
|
|
86569b0599 | ||
|
|
45aa2f72cb | ||
|
|
06b7434ca2 | ||
|
|
258cebda6e | ||
|
|
0cca43c4bd | ||
|
|
bf40a1038e | ||
|
|
3312a66e75 | ||
|
|
4a31d6b3bc | ||
|
|
64dfc6e191 | ||
|
|
95bd7f9861 | ||
|
|
983549711c | ||
|
|
5922dbdf22 | ||
|
|
9e48a5b57b | ||
|
|
3c1114403e | ||
|
|
8d2f614af6 | ||
|
|
1415de858c | ||
|
|
59e9fddf18 | ||
|
|
ad3b6cf629 | ||
|
|
b12e2eded5 | ||
|
|
26030d83eb | ||
|
|
3b01f6431e | ||
|
|
a646867593 | ||
|
|
768e61e11a | ||
|
|
e72ad9eb5a | ||
|
|
ac4faf673d | ||
|
|
dd1769fbef | ||
|
|
853a986082 | ||
|
|
727a3742f5 | ||
|
|
478a0b6a3f | ||
|
|
771688a70f | ||
|
|
40fa549353 | ||
|
|
84fdc1e690 | ||
|
|
71bbb41b5f | ||
|
|
52cb72ba67 | ||
|
|
54a3b754e0 | ||
|
|
2bc88e7750 | ||
|
|
ef59cb47dd | ||
|
|
9e5d3aa286 | ||
|
|
25bf25eae6 | ||
|
|
24f5fa66f3 | ||
|
|
1aeb2d7d4f | ||
|
|
ee176f5bfd | ||
|
|
eb093b8e6c | ||
|
|
f88fa6e3b2 | ||
|
|
724f7d4f3d | ||
|
|
19816d8814 | ||
|
|
d3b170c6df | ||
|
|
757091beeb | ||
|
|
8a49039b85 | ||
|
|
4f39cd1d7f | ||
|
|
2a6277c0c3 | ||
|
|
33bd6aed20 | ||
|
|
b9980c9d30 | ||
|
|
01bb94514c | ||
|
|
d71967ea1d | ||
|
|
0b06d0bfdb | ||
|
|
b2a83018ba | ||
|
|
ba265d94f4 | ||
|
|
af7b314cfe | ||
|
|
4c6447a3da | ||
|
|
b30f771fa2 | ||
|
|
837c0402a0 | ||
|
|
e38219aa2e | ||
|
|
9e92f6da3d | ||
|
|
44551ea9ee | ||
|
|
c53da9b1ff | ||
|
|
e1785dbd9a | ||
|
|
2560a9b78c | ||
|
|
d53e989c55 | ||
|
|
211a841cdb | ||
|
|
50e4365475 | ||
|
|
c524b54af1 | ||
|
|
7591bb115e | ||
|
|
3d2da303c8 | ||
|
|
f585eb6e62 | ||
|
|
4b6120a46b | ||
|
|
d946c6d5ed | ||
|
|
5894b85bd1 | ||
|
|
3fc43f7d92 | ||
|
|
8ed264460f | ||
|
|
811b32735e | ||
|
|
4b3db0c4d2 | ||
|
|
281ba21298 | ||
|
|
d4a177949a | ||
|
|
a42d8c9229 | ||
|
|
dd0e407935 | ||
|
|
7ef5b39b04 | ||
|
|
cf9121dfc2 | ||
|
|
fcfc2a65a9 | ||
|
|
91accb0bc6 | ||
|
|
e2abe8840f | ||
|
|
ead9ae8cb5 | ||
|
|
455719936b | ||
|
|
8d56fc71fa | ||
|
|
833d154bf4 | ||
|
|
f31dc5abc7 | ||
|
|
9a429230fe | ||
|
|
b36d46b7f2 | ||
|
|
fee89665fd | ||
|
|
d78a37f9e3 | ||
|
|
28c5c02ef1 | ||
|
|
8ffeae38bc | ||
|
|
f4fae7938e | ||
|
|
22920bc9a1 | ||
|
|
ceb82cb863 | ||
|
|
1caa361e22 | ||
|
|
da20790238 | ||
|
|
f359dd0cd4 | ||
|
|
bee442a21f | ||
|
|
a66765e99b | ||
|
|
0db7f91eb4 | ||
|
|
850315dc20 | ||
|
|
d35e4bea01 | ||
|
|
356b623148 | ||
|
|
3a022e7a83 | ||
|
|
64945cec16 | ||
|
|
26741bdb53 | ||
|
|
7aa5e857ed | ||
|
|
2e277bf487 | ||
|
|
e4f46c6e14 | ||
|
|
e9d90644fd | ||
|
|
5a06f0dce9 | ||
|
|
08e9a58f2e | ||
|
|
e1f0c8e87c | ||
|
|
17a532f7b5 | ||
|
|
c7306dda12 | ||
|
|
00d311cd6c | ||
|
|
f8d2a7f449 | ||
|
|
a02a928996 | ||
|
|
eb661b7a24 | ||
|
|
6aea607f21 | ||
|
|
41e747dcc1 | ||
|
|
d3d02faa1c | ||
|
|
7a85a3c7f7 | ||
|
|
fceb2851ef | ||
|
|
2f118781ea | ||
|
|
b8e3a45a7e | ||
|
|
61312397e1 | ||
|
|
8ea4682aab | ||
|
|
3b6befdb97 | ||
|
|
613979ea3f | ||
|
|
191def686b | ||
|
|
f986e0dc78 | ||
|
|
08e75567d4 | ||
|
|
668199f1a8 | ||
|
|
7a753a56ec | ||
|
|
7b38b4e280 | ||
|
|
7dc2e2ca73 | ||
|
|
44eb23615a | ||
|
|
d47566f667 | ||
|
|
9ae84c8108 | ||
|
|
578c7aac35 | ||
|
|
1c460cc19c | ||
|
|
ff436aea93 | ||
|
|
aa333794f7 | ||
|
|
3d3593a1a9 | ||
|
|
257062e20c | ||
|
|
fa9d7afb46 | ||
|
|
ae5f351e1a | ||
|
|
257a88ec8e | ||
|
|
e1e6304a8a | ||
|
|
a81ef0017c | ||
|
|
b89162e086 | ||
|
|
a6630540a4 | ||
|
|
a528c5d54b | ||
|
|
690699ddf7 | ||
|
|
cd8d9c657e | ||
|
|
f732b80b92 | ||
|
|
ad8c12afa5 | ||
|
|
479fcb6c46 | ||
|
|
74874dfff2 | ||
|
|
ceb108a5fe | ||
|
|
235d8b7cf0 | ||
|
|
7c9df2d75a | ||
|
|
43bf75217f | ||
|
|
9bf6d478c5 | ||
|
|
e2baa93270 | ||
|
|
37fcda3817 | ||
|
|
457ae54341 | ||
|
|
4cc3c5ada9 | ||
|
|
07d5736d61 | ||
|
|
a7551a44e5 | ||
|
|
f4d3e13c7f | ||
|
|
47d82b3d35 | ||
|
|
9d06aff1d1 | ||
|
|
5ea8c978a0 | ||
|
|
6809c3a9f6 | ||
|
|
761108964e | ||
|
|
e3e74a84f2 | ||
|
|
1fee4e87c4 | ||
|
|
0c4c59375d | ||
|
|
09165daab8 | ||
|
|
3393b77535 | ||
|
|
d050bc02e2 | ||
|
|
af60ddf404 | ||
|
|
1bb92f63d1 | ||
|
|
a405ca39fa | ||
|
|
852b686d81 | ||
|
|
608d5d3c26 | ||
|
|
6038ebb705 | ||
|
|
4bb350d37d | ||
|
|
d01ac55db1 | ||
|
|
fcde5c3c18 | ||
|
|
dbf19e134f | ||
|
|
b13c5a3b8b | ||
|
|
b0c5a352c1 | ||
|
|
d0b3cd5f66 | ||
|
|
24efdec9ea | ||
|
|
1bed818a8e | ||
|
|
3c4c52567d | ||
|
|
87ae14d11c | ||
|
|
258d303e7f | ||
|
|
458350e1a8 | ||
|
|
fe7ee1e2c7 | ||
|
|
d8910a0097 | ||
|
|
3b6e683d37 | ||
|
|
90f6bad6ce | ||
|
|
fcc6802f86 | ||
|
|
3b9bc77ecc | ||
|
|
0fb4500fcc | ||
|
|
93ca00c7fe | ||
|
|
522f2a3f9f | ||
|
|
40ddf5f49c | ||
|
|
60356eacce | ||
|
|
158f3bf092 | ||
|
|
ebf3c65bed | ||
|
|
df6d1d72e2 | ||
|
|
72542322ca | ||
|
|
fea4f3f973 | ||
|
|
7878180f54 | ||
|
|
0669aa6bbd | ||
|
|
2c4924a602 | ||
|
|
bde86e0383 | ||
|
|
bab18275bc | ||
|
|
7e86681509 | ||
|
|
c2fc2df54c | ||
|
|
0deb77468f | ||
|
|
9bf1d3e0c6 | ||
|
|
3a12d28d20 | ||
|
|
e8ba4bdc6c | ||
|
|
b552973e00 | ||
|
|
ac98e1fd0f | ||
|
|
4246aac51b | ||
|
|
33f396bdae | ||
|
|
ff25cecd54 | ||
|
|
e88b258208 | ||
|
|
1cbf895e0e | ||
|
|
7dc1f5c445 | ||
|
|
439e049948 | ||
|
|
fbf26bef8d | ||
|
|
c1f550382c | ||
|
|
23fb6a5c02 | ||
|
|
d632266092 | ||
|
|
4ea3ab9538 | ||
|
|
725161ea6e | ||
|
|
fccd86f676 | ||
|
|
0f0a977ed9 | ||
|
|
7f9d0b59b8 | ||
|
|
b0d510167c | ||
|
|
4971933201 | ||
|
|
693a9b30ae | ||
|
|
76c285158a | ||
|
|
08517e3732 | ||
|
|
59530f4263 | ||
|
|
5d48fb41ba | ||
|
|
4acebe7f59 | ||
|
|
a44a7b7161 | ||
|
|
be13f0a066 | ||
|
|
98ce77c2b1 | ||
|
|
275a491cac | ||
|
|
1c868f85c4 | ||
|
|
b6deacf86d | ||
|
|
ebe5ef6535 | ||
|
|
294f91473c | ||
|
|
902f04efb4 | ||
|
|
ca2989c0e5 | ||
|
|
2d9697cd66 | ||
|
|
b4111a9f79 | ||
|
|
7f8212fdba | ||
|
|
7e1be8a3a4 | ||
|
|
05aad07bfc | ||
|
|
92a80f9a58 | ||
|
|
4b4ceb525a | ||
|
|
42ba9888d7 | ||
|
|
818f912a90 | ||
|
|
dae64b82ff | ||
|
|
53c6edcbdb | ||
|
|
723172bc1f | ||
|
|
323b5d6694 | ||
|
|
441cd3fc59 | ||
|
|
1d23d1b2e2 | ||
|
|
1dd81b6d49 | ||
|
|
741e825ab9 | ||
|
|
e41811fbd0 | ||
|
|
f111106a9f | ||
|
|
f9e29eaede | ||
|
|
e7a6172d7e | ||
|
|
ec8f9228e8 | ||
|
|
6c12e26632 | ||
|
|
9a6ac7bd20 | ||
|
|
5b3751da70 | ||
|
|
65127eb226 | ||
|
|
115e0a6fee | ||
|
|
ddfab44883 | ||
|
|
6eab390962 | ||
|
|
35388056d3 | ||
|
|
e2c5967191 | ||
|
|
7cdb967810 | ||
|
|
8900d52c33 | ||
|
|
bab72393e6 | ||
|
|
e059c25ebc | ||
|
|
c87ca8f5dc | ||
|
|
e01e3cdd43 | ||
|
|
2ab9ade761 | ||
|
|
0b35b8f6d6 | ||
|
|
9ff95f66dd | ||
|
|
c1523c4936 | ||
|
|
b6e31278a7 | ||
|
|
ca2b24f735 | ||
|
|
2b0bca8e55 | ||
|
|
98fe7e8700 | ||
|
|
0acc3cc537 | ||
|
|
8491ffde07 | ||
|
|
2ea3989497 | ||
|
|
e6f9592cde | ||
|
|
222d79bf53 | ||
|
|
19d9258717 | ||
|
|
b46456b78e | ||
|
|
cebc2ef09d | ||
|
|
c4ff8f6876 | ||
|
|
619022ef7f | ||
|
|
c0f3c5b3db | ||
|
|
860b8bf945 | ||
|
|
694db81b80 | ||
|
|
a895270bc8 | ||
|
|
7474b451ca | ||
|
|
e8eecc8bc1 | ||
|
|
28e33b413c | ||
|
|
78c58e61ea | ||
|
|
f3ecdf21bf | ||
|
|
ff656365d2 | ||
|
|
ea7c09bb00 | ||
|
|
e23f7cd3e7 | ||
|
|
c6bb32b862 | ||
|
|
0bde69b441 | ||
|
|
6fbafb74bd | ||
|
|
9572c1f663 | ||
|
|
0fedb0f2c5 | ||
|
|
33d3aef9f5 | ||
|
|
fb8ccedf66 | ||
|
|
efcf0accc1 | ||
|
|
f556d5c07d | ||
|
|
6c1f424c0b | ||
|
|
90970f97e8 | ||
|
|
d3137dc6b9 | ||
|
|
efaf53f2f7 | ||
|
|
beb7b89275 | ||
|
|
8c15fa1627 | ||
|
|
bc814c9be6 | ||
|
|
bac7ef71d8 | ||
|
|
dd199ea30f | ||
|
|
fc8acac1a5 | ||
|
|
fec269c3e7 | ||
|
|
8e366fd633 | ||
|
|
f7d54186dd | ||
|
|
ab92fb3910 | ||
|
|
6783e2e28b | ||
|
|
4e47d3f458 | ||
|
|
b265c7dcb7 | ||
|
|
f4fae89b8e | ||
|
|
45f0b4c85f | ||
|
|
7c80483f6e | ||
|
|
08ba4fdbee | ||
|
|
7085796601 | ||
|
|
091b5f73b1 | ||
|
|
0c079edc1a | ||
|
|
54cdfb89f6 | ||
|
|
f56514ed7d | ||
|
|
56697fde19 | ||
|
|
80525ee736 | ||
|
|
a43bdd9aad | ||
|
|
20360d0bb0 | ||
|
|
70d7513f84 | ||
|
|
12b7fd3ab4 | ||
|
|
c32b5b5429 | ||
|
|
ea2a748dba | ||
|
|
c1d7d8c55a | ||
|
|
a3c58d8445 | ||
|
|
cfc5c2aef6 | ||
|
|
313260a0c5 | ||
|
|
ee548aaf83 | ||
|
|
5eab57e500 | ||
|
|
6f48fdad42 | ||
|
|
98fb5109d7 | ||
|
|
9c2ead16cc | ||
|
|
c4293c6119 | ||
|
|
13c392d758 | ||
|
|
35f10518b2 | ||
|
|
03066c4674 | ||
|
|
e33a6892b3 | ||
|
|
87bb3f4a6b | ||
|
|
62bfaa4e45 | ||
|
|
9e94e605ee | ||
|
|
f8dc647b1f | ||
|
|
fc727d6909 | ||
|
|
c1d61dc624 | ||
|
|
0627ca2fc2 | ||
|
|
ce0b064972 | ||
|
|
2f3f04e4ca | ||
|
|
2e91f27336 | ||
|
|
10b1829830 | ||
|
|
4946f32d88 | ||
|
|
dc1363aaf5 | ||
|
|
a5067718d2 | ||
|
|
98505a9a3f | ||
|
|
e054fdb464 | ||
|
|
3c8ad18693 | ||
|
|
0a91f571c1 | ||
|
|
8db5284f6e | ||
|
|
22aa695508 | ||
|
|
a16f733622 | ||
|
|
af7d6c8cb5 | ||
|
|
693f455862 | ||
|
|
b0abd290a9 | ||
|
|
f10290246f | ||
|
|
0a9686f584 | ||
|
|
0b11bf6266 | ||
|
|
d26056d272 | ||
|
|
724f9ec76f | ||
|
|
d583c79936 | ||
|
|
73b47716bc | ||
|
|
4eaef94454 | ||
|
|
21c9c7b8f4 | ||
|
|
108fb12612 | ||
|
|
eb8a030966 | ||
|
|
9235bb35a1 | ||
|
|
7b281abf0c | ||
|
|
b5fecd30cf | ||
|
|
26ff50f85c | ||
|
|
2eb1ba565f | ||
|
|
4dbb869952 | ||
|
|
f3041a8d7e | ||
|
|
4109cdec53 | ||
|
|
cdced887d1 | ||
|
|
77ca922f62 | ||
|
|
a08166f27d | ||
|
|
b9c56d1885 | ||
|
|
fcbacd473d | ||
|
|
06d77d9972 | ||
|
|
ee9c4f130e | ||
|
|
ada729087d | ||
|
|
aa47a72656 | ||
|
|
857ec70abb | ||
|
|
149f837223 | ||
|
|
37d6529ae0 | ||
|
|
8d3ae65e04 | ||
|
|
649e539ca6 | ||
|
|
45e90750a0 | ||
|
|
ce2a8917a6 | ||
|
|
b22cd2d27c | ||
|
|
813ef7d81a | ||
|
|
88275cd968 | ||
|
|
3a47563b27 | ||
|
|
ebb45a866b | ||
|
|
1433822437 | ||
|
|
4a5b416a0b | ||
|
|
cad4efdded | ||
|
|
f73a8d4d80 | ||
|
|
dac19d224f | ||
|
|
fa3e5eebe2 | ||
|
|
b64749c9d7 | ||
|
|
822165f168 | ||
|
|
2d16463fc6 | ||
|
|
3d8cbe9427 | ||
|
|
f18b64faaf | ||
|
|
95c7a7e9de | ||
|
|
ca152ab04c | ||
|
|
bf8bba7b84 | ||
|
|
3f2f699449 | ||
|
|
6b68a39cbe | ||
|
|
8867840215 | ||
|
|
1c516daa96 | ||
|
|
21c9388ee6 | ||
|
|
c72146587a | ||
|
|
0ba685d0e2 | ||
|
|
ce98f46331 | ||
|
|
d6aa672556 | ||
|
|
6d2761b155 | ||
|
|
127afe1582 | ||
|
|
a3d7f4e35d | ||
|
|
8eb163532d | ||
|
|
ea50023ca5 | ||
|
|
846aef1bd6 | ||
|
|
143f2eb1a8 | ||
|
|
3f8cb23cf6 | ||
|
|
f92709b03b | ||
|
|
81bb7c6534 | ||
|
|
bdd1074be7 | ||
|
|
42a63f8ea5 | ||
|
|
3c85db1769 | ||
|
|
930d5b3627 | ||
|
|
a1ec40b547 | ||
|
|
022f9ea76e | ||
|
|
2681903c93 | ||
|
|
403d10cc75 | ||
|
|
66e88cef42 | ||
|
|
8f9d1b99e2 | ||
|
|
4af2f6d84a | ||
|
|
c919f6bca0 | ||
|
|
51b421a165 | ||
|
|
86ff54e844 | ||
|
|
b8cb3f5815 | ||
|
|
381a51271f | ||
|
|
10500178d5 | ||
|
|
78fa4feac6 | ||
|
|
e81e66f40d | ||
|
|
f6bd74aadf | ||
|
|
5189f38766 | ||
|
|
243e888717 | ||
|
|
c5b81f2f4b | ||
|
|
caa14e0cad | ||
|
|
322c2804fc | ||
|
|
d411a9e1ff | ||
|
|
3fbc850774 | ||
|
|
d16febcae1 | ||
|
|
26bb6cc011 | ||
|
|
bc80ef9a80 | ||
|
|
9fad0876c5 | ||
|
|
914e635b4a | ||
|
|
85bb234cf9 | ||
|
|
f7675a5dea | ||
|
|
7b662055dd | ||
|
|
d78c6f1a74 | ||
|
|
9fa83d1cee | ||
|
|
6e780164ea | ||
|
|
2ca8da0710 | ||
|
|
c3deabae36 | ||
|
|
9cdbcb72ac | ||
|
|
bc86590411 | ||
|
|
cb167f3d74 | ||
|
|
8ddc99e91f | ||
|
|
dcc9af946a | ||
|
|
e4e3b199fc | ||
|
|
bf61c82cf2 | ||
|
|
c9ee28ce01 | ||
|
|
5135beb036 | ||
|
|
f36ef86ccc | ||
|
|
5e042bf4b8 | ||
|
|
130ce34686 | ||
|
|
591ef540a6 | ||
|
|
697f6ab538 | ||
|
|
ba5b5db2c4 | ||
|
|
e7afbab6a1 | ||
|
|
5298cb8cfb | ||
|
|
777bece2eb | ||
|
|
7daad1a52a | ||
|
|
60fd3c6bd3 | ||
|
|
dc1c82f347 | ||
|
|
c7a58816b6 | ||
|
|
48c3cb4816 | ||
|
|
6e7f2107cb | ||
|
|
101b835cf6 | ||
|
|
558a90aaf8 | ||
|
|
1d4161ba31 | ||
|
|
78d53af27c | ||
|
|
188b4424e4 | ||
|
|
0615d635eb | ||
|
|
85d7e75fb1 | ||
|
|
833559dde6 | ||
|
|
b294cee278 | ||
|
|
afe7ddb480 | ||
|
|
98526af82a | ||
|
|
0cb4562254 | ||
|
|
70f0ee719c | ||
|
|
63b120e9e2 | ||
|
|
d587120613 | ||
|
|
0dc4bc3cee | ||
|
|
79aad225a4 | ||
|
|
8cd2bc7c13 | ||
|
|
2a5198cae4 | ||
|
|
b8c463db82 | ||
|
|
059b016c62 | ||
|
|
f1429632d2 | ||
|
|
2d34208269 | ||
|
|
36c9054744 | ||
|
|
5e11efb0b9 | ||
|
|
703988b376 | ||
|
|
fefd2677fb | ||
|
|
a323aeb8fa | ||
|
|
8d6b0e23ce | ||
|
|
edac99e5a9 | ||
|
|
dd14235e31 | ||
|
|
15eadd4f89 | ||
|
|
09fbb045a1 | ||
|
|
7bdd0d3bf1 | ||
|
|
ebea9a7198 | ||
|
|
ad9441bb60 | ||
|
|
989f9dce42 | ||
|
|
b95437347e | ||
|
|
2d27e0d9a9 | ||
|
|
c3c078e5be | ||
|
|
dd8eb29a18 | ||
|
|
2d5591a87f | ||
|
|
71b079eb54 | ||
|
|
ca6f3807fc | ||
|
|
c2f6a6983d | ||
|
|
3891ca2929 | ||
|
|
20437ef2c7 | ||
|
|
7de02d541f | ||
|
|
68e4c5e469 | ||
|
|
62187807f0 | ||
|
|
37f4caf536 | ||
|
|
fca1c6e957 | ||
|
|
0de7e71fa0 | ||
|
|
fd5d540c78 | ||
|
|
d2069dc5f2 | ||
|
|
2ac832678f | ||
|
|
5941332d49 | ||
|
|
45732bd87a | ||
|
|
f7600af89b | ||
|
|
5108121b59 | ||
|
|
c2339c84e7 | ||
|
|
7205c5cb7b | ||
|
|
ff807c9a6f | ||
|
|
0341eb5d8f | ||
|
|
a2e1b1de3a | ||
|
|
e64059bd7b | ||
|
|
46b1de97f5 | ||
|
|
ca7d2c6d64 | ||
|
|
12d4d4a4f7 | ||
|
|
7c92054f13 | ||
|
|
1bef1d5652 | ||
|
|
89a02383b8 | ||
|
|
7fba904f75 | ||
|
|
1c7741fdbe | ||
|
|
4c90a0ed7e | ||
|
|
a82b174826 | ||
|
|
579ff8c0b4 | ||
|
|
264080546c | ||
|
|
a0c65e2333 | ||
|
|
dd73ad544c | ||
|
|
33db9023eb | ||
|
|
88eea03f97 | ||
|
|
a959ec1eb1 | ||
|
|
3e138cbc6d | ||
|
|
9b61723194 | ||
|
|
d2381b0209 | ||
|
|
4972f69dd6 | ||
|
|
56eb220ed6 | ||
|
|
343c47d67a | ||
|
|
e53f2217ec | ||
|
|
016a5a5914 | ||
|
|
9f2adfb67a | ||
|
|
6e92e7283d | ||
|
|
e3c16147ce | ||
|
|
14aa9805b4 | ||
|
|
fdab17a3b9 | ||
|
|
bebba7d280 | ||
|
|
11b2b2a893 | ||
|
|
84141082ab | ||
|
|
ba29b5e036 | ||
|
|
e22421ec99 | ||
|
|
416b38fc71 | ||
|
|
fd5fcfeaae | ||
|
|
75ff268ecc | ||
|
|
9f98b8ad2f | ||
|
|
316035910f | ||
|
|
d1d09d4aab | ||
|
|
31365b266a | ||
|
|
2f34e7eeed | ||
|
|
3aff3ac7e4 | ||
|
|
d1a185aaae | ||
|
|
ff10432124 | ||
|
|
bb5b805983 | ||
|
|
58ae3479dc | ||
|
|
d55e007032 | ||
|
|
2af43d62eb | ||
|
|
5c527b2c48 | ||
|
|
e6165f0046 | ||
|
|
70427bc676 | ||
|
|
9ec7cbef8e | ||
|
|
719d841353 | ||
|
|
fa6af06204 | ||
|
|
cba719b3a0 | ||
|
|
4241bb08b8 | ||
|
|
901242f7e9 | ||
|
|
4c74e7f308 | ||
|
|
db48c15f1d | ||
|
|
a1b34e7a88 | ||
|
|
fc6b3726a4 | ||
|
|
9c9bcac61b | ||
|
|
588da4d7dc | ||
|
|
e42db3cd2d | ||
|
|
e8cc88174f | ||
|
|
7b7111e12c | ||
|
|
b3f2c60065 | ||
|
|
20e896cacf | ||
|
|
afbf7de9e3 | ||
|
|
4ff85ab0c4 | ||
|
|
dd7388e577 | ||
|
|
77f13961ad | ||
|
|
e00fe0a732 | ||
|
|
c757d21360 | ||
|
|
3a134cc706 | ||
|
|
7aede4d058 | ||
|
|
5983eae3a8 | ||
|
|
9d6dca9c64 | ||
|
|
7b68c1bc9b | ||
|
|
9d905368ca | ||
|
|
867613669d | ||
|
|
fd1de624c8 | ||
|
|
2a2247e1da | ||
|
|
7a59bee315 | ||
|
|
91c8a7c65b | ||
|
|
73a0b31380 | ||
|
|
ef00695b07 | ||
|
|
bfaffbc87e | ||
|
|
e800d62df4 | ||
|
|
6fe765434e | ||
|
|
7e48740ea7 | ||
|
|
d25a439bd4 | ||
|
|
ed8c85df2b | ||
|
|
c4ae8c3418 | ||
|
|
f87dce8ec1 | ||
|
|
5d2f1c8e11 | ||
|
|
1aa2852ed6 | ||
|
|
a42a406f53 | ||
|
|
47b56e78b3 | ||
|
|
52db7b32ef | ||
|
|
3aad5a30e9 | ||
|
|
b8a10f2e86 | ||
|
|
4e8dc0e3b9 | ||
|
|
edf60f80f7 | ||
|
|
a94c598d00 | ||
|
|
68abaa5e3c | ||
|
|
63b31de2b8 | ||
|
|
eac5c604bd | ||
|
|
e7d8df499c | ||
|
|
35845440c6 | ||
|
|
18926009d3 | ||
|
|
d55a9e6274 | ||
|
|
ba011581ef | ||
|
|
1788ceccea | ||
|
|
ada8255af0 | ||
|
|
f1a6f66d49 | ||
|
|
423793ecf9 | ||
|
|
94cfa3c9d0 | ||
|
|
0134ceef16 | ||
|
|
b23ce7462e | ||
|
|
cf3dda6869 | ||
|
|
dc8520df42 | ||
|
|
d9c5976ed0 | ||
|
|
aeea5701e4 | ||
|
|
7263e35a89 | ||
|
|
4d991d3773 | ||
|
|
bfcde15a24 | ||
|
|
ee675546ac | ||
|
|
b43e6c5d6b | ||
|
|
c531ef0773 | ||
|
|
a6a4c03029 | ||
|
|
b525cfc787 | ||
|
|
842aa97f7e | ||
|
|
34d4eedf67 | ||
|
|
4a109d6af1 | ||
|
|
cb40a76247 | ||
|
|
ed249600d3 | ||
|
|
0187c9d6df | ||
|
|
6da37966d9 | ||
|
|
525d4325c7 | ||
|
|
ecf7e25a51 | ||
|
|
ec2f8fe6c8 | ||
|
|
dfaf40f583 | ||
|
|
543154f037 | ||
|
|
cd3e355f84 | ||
|
|
2eee6b45bc | ||
|
|
0de5c6f204 | ||
|
|
9363fc153c | ||
|
|
2aacd5b9b6 | ||
|
|
c3b2e1e8b2 | ||
|
|
e261c197f3 | ||
|
|
747dc77c92 | ||
|
|
35cc7b27e9 | ||
|
|
67828a86c1 | ||
|
|
58ec31d6c7 | ||
|
|
6da0b57ce1 | ||
|
|
8d9d5a267a | ||
|
|
94af55a951 | ||
|
|
192cec1825 | ||
|
|
1e564c2140 | ||
|
|
7e008378ba | ||
|
|
dbc4ffd69a | ||
|
|
5a1e8d9fe9 | ||
|
|
5e5d30a377 | ||
|
|
3bc0def02a | ||
|
|
bd301880ad | ||
|
|
2deb703272 | ||
|
|
8c6489a49a | ||
|
|
87609ba5d1 | ||
|
|
ba3a51387c | ||
|
|
ffd5bfc480 | ||
|
|
a4226cc39a | ||
|
|
dcb89b704a | ||
|
|
686c7c5a6c | ||
|
|
409eea677d | ||
|
|
99d41d1606 | ||
|
|
915b7aa2df | ||
|
|
e2d5102a0e | ||
|
|
e5a41b60ef | ||
|
|
0572ea4095 | ||
|
|
71032150c5 | ||
|
|
36d13dd414 | ||
|
|
946e369a44 | ||
|
|
18922ed6f5 | ||
|
|
c1dd4dafe4 | ||
|
|
fe3aec173f | ||
|
|
de4fde4ee3 | ||
|
|
3450219bc7 | ||
|
|
6af126b872 | ||
|
|
ac42cba50b | ||
|
|
5d263f63cb | ||
|
|
f445186f1e | ||
|
|
bdd53ed5e3 | ||
|
|
dbd5ef70c9 | ||
|
|
ce9554281e | ||
|
|
4e1fba5b38 | ||
|
|
3f238f7a4a | ||
|
|
b89091cc7d | ||
|
|
992b76a0f0 | ||
|
|
2bcd51b21c | ||
|
|
3625453668 | ||
|
|
5821a122cc | ||
|
|
891e414cb6 | ||
|
|
54f9e3ff9d | ||
|
|
1c0cc15fdb | ||
|
|
231e07dbbd | ||
|
|
3859f6464a | ||
|
|
71a74a6656 | ||
|
|
3668d1aadf | ||
|
|
d3af06e7a4 | ||
|
|
74f2a61b25 | ||
|
|
68a667ee7c | ||
|
|
192b5db25a | ||
|
|
9ced391c11 | ||
|
|
807b525c79 | ||
|
|
7bd04deae7 | ||
|
|
c379822bf0 | ||
|
|
ad67167e97 | ||
|
|
4012a8276c | ||
|
|
efc028d0a5 | ||
|
|
01a121e029 | ||
|
|
f793450d97 | ||
|
|
fec868432f | ||
|
|
d3b08beb53 | ||
|
|
a75d4841d0 | ||
|
|
8b3730748b | ||
|
|
de5552c91a | ||
|
|
a7e6dec51d | ||
|
|
26335a9b42 | ||
|
|
f8dd6890b2 | ||
|
|
1c103f92f2 | ||
|
|
e3ce683970 | ||
|
|
9eb63b17f9 | ||
|
|
755370eff0 | ||
|
|
407ad51244 | ||
|
|
293fb0a76d | ||
|
|
2e228c8355 | ||
|
|
009f7617c1 | ||
|
|
b39c8c1f1f | ||
|
|
7b29c6427b | ||
|
|
d0e084b8ea | ||
|
|
46223e0b30 | ||
|
|
5d3b147b42 | ||
|
|
6474c296e1 | ||
|
|
b8ad80ae35 | ||
|
|
78240b4b52 | ||
|
|
e7c716ede4 | ||
|
|
da528e802f | ||
|
|
23b4327c28 | ||
|
|
9f6dfa4d2e | ||
|
|
728d1f7540 | ||
|
|
ee92ba20b0 | ||
|
|
1b749cf004 | ||
|
|
37929dbd7d | ||
|
|
865ba912f8 | ||
|
|
9dbb9f519b | ||
|
|
20188549f7 | ||
|
|
925be17d51 | ||
|
|
0ea4c99102 | ||
|
|
db98b7ed27 | ||
|
|
44de611097 | ||
|
|
a5ee8fb59d | ||
|
|
e532804474 | ||
|
|
ce24781446 | ||
|
|
c867d6648a | ||
|
|
8ae5ae7e57 | ||
|
|
6a639edb05 | ||
|
|
a1a79719fc | ||
|
|
c5f99b012e | ||
|
|
fcd1bea4a3 | ||
|
|
0622c77a7f | ||
|
|
8aaf3e1052 | ||
|
|
3dcaa1f6fb | ||
|
|
2d91e509fa | ||
|
|
a0f1839162 | ||
|
|
e2f52765e4 | ||
|
|
f186a3dde9 | ||
|
|
9b065155f4 | ||
|
|
12306368cf | ||
|
|
d4e8ea8e72 | ||
|
|
619402cc67 | ||
|
|
b01bfda862 | ||
|
|
da19df5174 | ||
|
|
19dd9b97d2 | ||
|
|
21b92ac077 | ||
|
|
b80dd1ef3e | ||
|
|
d6b9154a88 | ||
|
|
f9573f7972 | ||
|
|
038cadeae8 | ||
|
|
e32ca284c5 | ||
|
|
a56426010d | ||
|
|
dda07af4d4 | ||
|
|
81bfb202f7 | ||
|
|
b6561fd8e2 | ||
|
|
d475e50bef | ||
|
|
689a01423f | ||
|
|
888d637b67 | ||
|
|
e7660d68cb | ||
|
|
450a01784b | ||
|
|
5d8cb511be | ||
|
|
44ad8ce888 | ||
|
|
14572d9eab | ||
|
|
76d735ff43 | ||
|
|
02b621bd2c | ||
|
|
96eab86bc6 | ||
|
|
93ee96b1cd | ||
|
|
907dbe6388 | ||
|
|
f8e01d5d53 | ||
|
|
454b541a2e | ||
|
|
2b9b22cd90 | ||
|
|
5584c4f1ae | ||
|
|
9830f661c8 | ||
|
|
7a21c44727 | ||
|
|
4c55e5a6cc | ||
|
|
f0012015e6 | ||
|
|
14557983e1 | ||
|
|
865e5cb120 | ||
|
|
d9cb018a7d | ||
|
|
8dd9564171 | ||
|
|
77533f7873 | ||
|
|
a6b2eefee1 | ||
|
|
4cea08c080 | ||
|
|
d56e66917a | ||
|
|
28982e0e0b | ||
|
|
1fbf77d090 | ||
|
|
6c8a2e68d9 | ||
|
|
f5ddb084b6 | ||
|
|
21077ef26e | ||
|
|
5cedf98f55 | ||
|
|
a7247e9812 | ||
|
|
c9298137b5 | ||
|
|
17c95723ec | ||
|
|
1f654d4444 | ||
|
|
0a01d7b041 | ||
|
|
b53017ee87 | ||
|
|
af86a9dac0 | ||
|
|
d792c65ce3 | ||
|
|
8eef574342 | ||
|
|
2d0594398c | ||
|
|
115764ae38 | ||
|
|
5cda35db0a | ||
|
|
4f3b3a787c | ||
|
|
8e55e0b994 | ||
|
|
30c6d4756a | ||
|
|
d1150f150f | ||
|
|
e0f4abaa09 | ||
|
|
889e624a8c | ||
|
|
cd0ab5c709 | ||
|
|
d75fafb19c | ||
|
|
11c3f14b42 | ||
|
|
53528d486c | ||
|
|
3a8aea0de6 | ||
|
|
a3e11f017b | ||
|
|
c4da576030 | ||
|
|
465253a769 | ||
|
|
3b74d987c1 | ||
|
|
3385ba2ca2 | ||
|
|
6dba2879c5 | ||
|
|
8fc1656939 | ||
|
|
75012cdcba | ||
|
|
c1e4c4cb30 | ||
|
|
a3a0af64ce | ||
|
|
1f9e5ca3cc | ||
|
|
7409f15752 |
39
CONTRIBUTING.md
Normal file
39
CONTRIBUTING.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Contributing to Security Onion
|
||||||
|
|
||||||
|
### Questions, suggestions, and general comments
|
||||||
|
* Security Onion uses GitHub's [Discussions](https://github.com/Security-Onion-Solutions/securityonion/discussions) to provide a forum where the community and developers can interact as well as ask and answer questions.
|
||||||
|
|
||||||
|
### Reporting a bug
|
||||||
|
* The primary place to report unexpected behavior or possible bugs is the repo's [Discussions forum](https://github.com/Security-Onion-Solutions/securityonion/discussions).
|
||||||
|
|
||||||
|
* **If you are familiar with the current version of Security Onion and are confident you've discovered a bug**, first ensure there is not already an issue present by searching the open [issues](https://github.com/Security-Onion-Solutions/securityonion/issues). If there is, a thumbs up :+1: is a great way to show this bug is affecting you too.
|
||||||
|
|
||||||
|
* If an issue doesn't exist, [open a new one](https://github.com/Security-Onion-Solutions/securityonion/issues/new), following the directions in the issue template. This means including:
|
||||||
|
* **System information** and how Security Onion was installed
|
||||||
|
* **Log files** relevant to the bug report
|
||||||
|
* **Reproduction steps**
|
||||||
|
|
||||||
|
### Contributing code
|
||||||
|
|
||||||
|
* **All commits must be signed** with a valid key that has been added to your GitHub account. Each commit should have the "**Verified**" tag when viewed on GitHub as shown below:
|
||||||
|
|
||||||
|
<img src="./assets/images/verified-commit-1.png" width="450">
|
||||||
|
|
||||||
|
* If an issue does not already exist for the bug or feature for which you are submitting a pull request, [create one](https://github.com/Security-Onion-Solutions/securityonion/issues/new) with the relevant prefix. (**`FIX:`** for bug fixes, **`FEATURE:`** for new features.)
|
||||||
|
|
||||||
|
* Link the PR to the related issue, either using [keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) in the PR description, or [manually](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue).
|
||||||
|
|
||||||
|
* **Pull requests should be opened against the `dev` branch of this repo**, and should clearly describe the problem and solution.
|
||||||
|
|
||||||
|
* Be sure you have tested your changes and are confident they will not break other parts of the product.
|
||||||
|
|
||||||
|
* See this document's [code styling and conventions section](#code-style-and-conventions) below to be sure your PR fits our code requirements prior to submitting.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Code style and conventions
|
||||||
|
* **Keep code [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)**. For example, Bash code used by multiple scripts will likely best be added to <span style="white-space: nowrap;">[`so-common`](salt/common/tools/sbin/so-common)</span>.
|
||||||
|
|
||||||
|
* All new Bash code should pass [ShellCheck](https://www.shellcheck.net/) analysis. Where errors can be *safely* [ignored](https://github.com/koalaman/shellcheck/wiki/Ignore), the relevant disable directive should be accompanied by a brief explanation as to why the error is being ignored.
|
||||||
|
|
||||||
|
* **Ensure all YAML (this includes Salt states and pillars) is properly formatted**. The spec for YAML v1.2 can be found [here](https://yaml.org/spec/1.2/spec.html), however there are numerous online resources with simpler descriptions of its formatting rules.
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
## Security Onion 2.3.51
|
## Security Onion 2.3.80
|
||||||
|
|
||||||
Security Onion 2.3.51 is here!
|
Security Onion 2.3.80 is here!
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
Alerts
|
Alerts
|
||||||

|

|
||||||
|
|
||||||
Hunt
|
Hunt
|
||||||

|

|
||||||
|
|
||||||
### Release Notes
|
### Release Notes
|
||||||
|
|
||||||
|
|||||||
21
SECURITY.md
Normal file
21
SECURITY.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 2.x.x | :white_check_mark: |
|
||||||
|
| 16.04.x | :x: |
|
||||||
|
|
||||||
|
Security Onion 16.04 has reached End Of Life and is no longer supported.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you have any security concerns regarding Security Onion or believe you have uncovered a vulnerability, please follow these steps:
|
||||||
|
|
||||||
|
- send an email to security@securityonion.net
|
||||||
|
- include a description of the issue and steps to reproduce
|
||||||
|
- please use plain text format (no Word documents or PDF files)
|
||||||
|
- please do not disclose publicly until we have had sufficient time to resolve the issue
|
||||||
|
|
||||||
|
This security address should be used only for undisclosed vulnerabilities. Dealing with fixed issues or general questions on how to use Security Onion should be handled via the normal support channels.
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
### 2.3.51 ISO image built on 2021/04/27
|
### 2.3.80 ISO image built on 2021/09/27
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Download and Verify
|
### Download and Verify
|
||||||
|
|
||||||
2.3.51 ISO image:
|
2.3.80 ISO image:
|
||||||
https://download.securityonion.net/file/securityonion/securityonion-2.3.51.iso
|
https://download.securityonion.net/file/securityonion/securityonion-2.3.80.iso
|
||||||
|
|
||||||
MD5: 7CFB525BEFC0A9F2ED148F5831E387FA
|
MD5: 24F38563860416F4A8ABE18746913E14
|
||||||
SHA1: 8CC34FCCC36822B309B8168AA706B3D1EC7F3BFD
|
SHA1: F923C005F54EA2A17AB225ADA0DA46042707AAD9
|
||||||
SHA256: 9892C2546C9AE5A48015160F379B070F0BE30C89693B97F3F1E1592DDCE1DEE0
|
SHA256: 8E95D10AF664D9A406C168EC421D943CB23F0D0C1813C6C2DBA9B4E131984018
|
||||||
|
|
||||||
Signature for ISO image:
|
Signature for ISO image:
|
||||||
https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.51.iso.sig
|
https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.80.iso.sig
|
||||||
|
|
||||||
Signing key:
|
Signing key:
|
||||||
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS
|
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS
|
||||||
@@ -25,22 +26,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/ma
|
|||||||
|
|
||||||
Download the signature file for the ISO:
|
Download the signature file for the ISO:
|
||||||
```
|
```
|
||||||
wget https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.51.iso.sig
|
wget https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.80.iso.sig
|
||||||
```
|
```
|
||||||
|
|
||||||
Download the ISO image:
|
Download the ISO image:
|
||||||
```
|
```
|
||||||
wget https://download.securityonion.net/file/securityonion/securityonion-2.3.51.iso
|
wget https://download.securityonion.net/file/securityonion/securityonion-2.3.80.iso
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify the downloaded ISO image using the signature file:
|
Verify the downloaded ISO image using the signature file:
|
||||||
```
|
```
|
||||||
gpg --verify securityonion-2.3.51.iso.sig securityonion-2.3.51.iso
|
gpg --verify securityonion-2.3.80.iso.sig securityonion-2.3.80.iso
|
||||||
```
|
```
|
||||||
|
|
||||||
The output should show "Good signature" and the Primary key fingerprint should match what's shown below:
|
The output should show "Good signature" and the Primary key fingerprint should match what's shown below:
|
||||||
```
|
```
|
||||||
gpg: Signature made Thu 20 May 2021 07:49:57 AM EDT using RSA key ID FE507013
|
gpg: Signature made Mon 27 Sep 2021 08:55:01 AM EDT using RSA key ID FE507013
|
||||||
gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>"
|
gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>"
|
||||||
gpg: WARNING: This key is not certified with a trusted signature!
|
gpg: WARNING: This key is not certified with a trusted signature!
|
||||||
gpg: There is no indication that the signature belongs to the owner.
|
gpg: There is no indication that the signature belongs to the owner.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 245 KiB After Width: | Height: | Size: 245 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
BIN
assets/images/verified-commit-1.png
Normal file
BIN
assets/images/verified-commit-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -16,6 +16,10 @@ firewall:
|
|||||||
ips:
|
ips:
|
||||||
delete:
|
delete:
|
||||||
insert:
|
insert:
|
||||||
|
endgame:
|
||||||
|
ips:
|
||||||
|
delete:
|
||||||
|
insert:
|
||||||
fleet:
|
fleet:
|
||||||
ips:
|
ips:
|
||||||
delete:
|
delete:
|
||||||
|
|||||||
@@ -67,3 +67,7 @@ peer:
|
|||||||
reactor:
|
reactor:
|
||||||
- 'so/fleet':
|
- 'so/fleet':
|
||||||
- salt://reactor/fleet.sls
|
- salt://reactor/fleet.sls
|
||||||
|
- 'salt/beacon/*/watch_sqlite_db//opt/so/conf/kratos/db/sqlite.db':
|
||||||
|
- salt://reactor/kratos.sls
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
templates:
|
templates:
|
||||||
- so/so-beats-template.json.jinja
|
- so/so-beats-template.json.jinja
|
||||||
- so/so-common-template.json
|
- so/so-common-template.json.jinja
|
||||||
- so/so-firewall-template.json.jinja
|
- so/so-firewall-template.json.jinja
|
||||||
- so/so-flow-template.json.jinja
|
- so/so-flow-template.json.jinja
|
||||||
- so/so-ids-template.json.jinja
|
- so/so-ids-template.json.jinja
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
templates:
|
templates:
|
||||||
- so/so-beats-template.json.jinja
|
- so/so-beats-template.json.jinja
|
||||||
- so/so-common-template.json
|
- so/so-common-template.json.jinja
|
||||||
|
- so/so-endgame-template.json.jinja
|
||||||
- so/so-firewall-template.json.jinja
|
- so/so-firewall-template.json.jinja
|
||||||
- so/so-flow-template.json.jinja
|
- so/so-flow-template.json.jinja
|
||||||
- so/so-ids-template.json.jinja
|
- so/so-ids-template.json.jinja
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
templates:
|
templates:
|
||||||
- so/so-beats-template.json.jinja
|
- so/so-beats-template.json.jinja
|
||||||
- so/so-common-template.json
|
- so/so-common-template.json.jinja
|
||||||
|
- so/so-endgame-template.json.jinja
|
||||||
- so/so-firewall-template.json.jinja
|
- so/so-firewall-template.json.jinja
|
||||||
- so/so-flow-template.json.jinja
|
- so/so-flow-template.json.jinja
|
||||||
- so/so-ids-template.json.jinja
|
- so/so-ids-template.json.jinja
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
logstash:
|
logstash:
|
||||||
docker_options:
|
docker_options:
|
||||||
port_bindings:
|
port_bindings:
|
||||||
|
- 0.0.0.0:3765:3765
|
||||||
- 0.0.0.0:5044:5044
|
- 0.0.0.0:5044:5044
|
||||||
- 0.0.0.0:5644:5644
|
- 0.0.0.0:5644:5644
|
||||||
- 0.0.0.0:6050:6050
|
- 0.0.0.0:6050:6050
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ logstash:
|
|||||||
config:
|
config:
|
||||||
- so/0009_input_beats.conf
|
- so/0009_input_beats.conf
|
||||||
- so/0010_input_hhbeats.conf
|
- so/0010_input_hhbeats.conf
|
||||||
|
- so/0011_input_endgame.conf
|
||||||
- so/9999_output_redis.conf.jinja
|
- so/9999_output_redis.conf.jinja
|
||||||
|
|
||||||
@@ -7,8 +7,11 @@ logstash:
|
|||||||
- so/9000_output_zeek.conf.jinja
|
- so/9000_output_zeek.conf.jinja
|
||||||
- so/9002_output_import.conf.jinja
|
- so/9002_output_import.conf.jinja
|
||||||
- so/9034_output_syslog.conf.jinja
|
- so/9034_output_syslog.conf.jinja
|
||||||
|
- so/9050_output_filebeatmodules.conf.jinja
|
||||||
- so/9100_output_osquery.conf.jinja
|
- so/9100_output_osquery.conf.jinja
|
||||||
- so/9400_output_suricata.conf.jinja
|
- so/9400_output_suricata.conf.jinja
|
||||||
- so/9500_output_beats.conf.jinja
|
- so/9500_output_beats.conf.jinja
|
||||||
- so/9600_output_ossec.conf.jinja
|
- so/9600_output_ossec.conf.jinja
|
||||||
- so/9700_output_strelka.conf.jinja
|
- so/9700_output_strelka.conf.jinja
|
||||||
|
- so/9800_output_logscan.conf.jinja
|
||||||
|
- so/9900_output_endgame.conf.jinja
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ base:
|
|||||||
'*':
|
'*':
|
||||||
- patch.needs_restarting
|
- patch.needs_restarting
|
||||||
- logrotate
|
- logrotate
|
||||||
|
- users
|
||||||
|
|
||||||
'*_eval or *_helixsensor or *_heavynode or *_sensor or *_standalone or *_import':
|
'*_eval or *_helixsensor or *_heavynode or *_sensor or *_standalone or *_import':
|
||||||
- match: compound
|
- match: compound
|
||||||
@@ -22,6 +23,12 @@ base:
|
|||||||
'*_manager or *_managersearch':
|
'*_manager or *_managersearch':
|
||||||
- match: compound
|
- match: compound
|
||||||
- data.*
|
- data.*
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
|
- elasticsearch.auth
|
||||||
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
|
- kibana.secrets
|
||||||
|
{% endif %}
|
||||||
- secrets
|
- secrets
|
||||||
- global
|
- global
|
||||||
- minions.{{ grains.id }}
|
- minions.{{ grains.id }}
|
||||||
@@ -38,6 +45,12 @@ base:
|
|||||||
- secrets
|
- secrets
|
||||||
- healthcheck.eval
|
- healthcheck.eval
|
||||||
- elasticsearch.eval
|
- elasticsearch.eval
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
|
- elasticsearch.auth
|
||||||
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
|
- kibana.secrets
|
||||||
|
{% endif %}
|
||||||
- global
|
- global
|
||||||
- minions.{{ grains.id }}
|
- minions.{{ grains.id }}
|
||||||
|
|
||||||
@@ -46,6 +59,12 @@ base:
|
|||||||
- logstash.manager
|
- logstash.manager
|
||||||
- logstash.search
|
- logstash.search
|
||||||
- elasticsearch.search
|
- elasticsearch.search
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
|
- elasticsearch.auth
|
||||||
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
|
- kibana.secrets
|
||||||
|
{% endif %}
|
||||||
- data.*
|
- data.*
|
||||||
- zeeklogs
|
- zeeklogs
|
||||||
- secrets
|
- secrets
|
||||||
@@ -59,6 +78,7 @@ base:
|
|||||||
|
|
||||||
'*_heavynode':
|
'*_heavynode':
|
||||||
- zeeklogs
|
- zeeklogs
|
||||||
|
- elasticsearch.auth
|
||||||
- global
|
- global
|
||||||
- minions.{{ grains.id }}
|
- minions.{{ grains.id }}
|
||||||
|
|
||||||
@@ -80,6 +100,7 @@ base:
|
|||||||
- logstash
|
- logstash
|
||||||
- logstash.search
|
- logstash.search
|
||||||
- elasticsearch.search
|
- elasticsearch.search
|
||||||
|
- elasticsearch.auth
|
||||||
- global
|
- global
|
||||||
- minions.{{ grains.id }}
|
- minions.{{ grains.id }}
|
||||||
- data.nodestab
|
- data.nodestab
|
||||||
@@ -88,5 +109,11 @@ base:
|
|||||||
- zeeklogs
|
- zeeklogs
|
||||||
- secrets
|
- secrets
|
||||||
- elasticsearch.eval
|
- elasticsearch.eval
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
|
||||||
|
- elasticsearch.auth
|
||||||
|
{% endif %}
|
||||||
|
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/kibana/secrets.sls') %}
|
||||||
|
- kibana.secrets
|
||||||
|
{% endif %}
|
||||||
- global
|
- global
|
||||||
- minions.{{ grains.id }}
|
- minions.{{ grains.id }}
|
||||||
2
pillar/users/init.sls
Normal file
2
pillar/users/init.sls
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# users pillar goes in /opt/so/saltstack/local/pillar/users/init.sls
|
||||||
|
# the users directory may need to be created under /opt/so/saltstack/local/pillar
|
||||||
19
pillar/users/pillar.example
Normal file
19
pillar/users/pillar.example
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
users:
|
||||||
|
sclapton:
|
||||||
|
# required fields
|
||||||
|
status: present
|
||||||
|
# node_access determines which node types the user can access.
|
||||||
|
# this can either be by grains.role or by final part of the minion id after the _
|
||||||
|
node_access:
|
||||||
|
- standalone
|
||||||
|
- searchnode
|
||||||
|
# optional fields
|
||||||
|
fullname: Stevie Claptoon
|
||||||
|
uid: 1001
|
||||||
|
gid: 1001
|
||||||
|
homephone: does not have a phone
|
||||||
|
groups:
|
||||||
|
- mygroup1
|
||||||
|
- mygroup2
|
||||||
|
- wheel # give sudo access
|
||||||
|
|
||||||
20
pillar/users/pillar.usage
Normal file
20
pillar/users/pillar.usage
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
users:
|
||||||
|
sclapton:
|
||||||
|
# required fields
|
||||||
|
status: <present | absent>
|
||||||
|
# node_access determines which node types the user can access.
|
||||||
|
# this can either be by grains.role or by final part of the minion id after the _
|
||||||
|
node_access:
|
||||||
|
- standalone
|
||||||
|
- searchnode
|
||||||
|
# optional fields
|
||||||
|
fullname: <string>
|
||||||
|
uid: <integer>
|
||||||
|
gid: <integer>
|
||||||
|
roomnumber: <string>
|
||||||
|
workphone: <string>
|
||||||
|
homephone: <string>
|
||||||
|
groups:
|
||||||
|
- <string>
|
||||||
|
- <string>
|
||||||
|
- wheel # give sudo access
|
||||||
@@ -52,5 +52,4 @@ zeek:
|
|||||||
- frameworks/signatures/detect-windows-shells
|
- frameworks/signatures/detect-windows-shells
|
||||||
redef:
|
redef:
|
||||||
- LogAscii::use_json = T;
|
- LogAscii::use_json = T;
|
||||||
- LogAscii::json_timestamps = JSON::TS_ISO8601;
|
|
||||||
- CaptureLoss::watch_interval = 5 mins;
|
- CaptureLoss::watch_interval = 5 mins;
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
'influxdb',
|
'influxdb',
|
||||||
'grafana',
|
'grafana',
|
||||||
'soc',
|
'soc',
|
||||||
|
'kratos',
|
||||||
'firewall',
|
'firewall',
|
||||||
'idstools',
|
'idstools',
|
||||||
'suricata.manager',
|
'suricata.manager',
|
||||||
@@ -45,7 +46,8 @@
|
|||||||
'schedule',
|
'schedule',
|
||||||
'soctopus',
|
'soctopus',
|
||||||
'tcpreplay',
|
'tcpreplay',
|
||||||
'docker_clean'
|
'docker_clean',
|
||||||
|
'learn'
|
||||||
],
|
],
|
||||||
'so-heavynode': [
|
'so-heavynode': [
|
||||||
'ca',
|
'ca',
|
||||||
@@ -99,6 +101,7 @@
|
|||||||
'manager',
|
'manager',
|
||||||
'nginx',
|
'nginx',
|
||||||
'soc',
|
'soc',
|
||||||
|
'kratos',
|
||||||
'firewall',
|
'firewall',
|
||||||
'idstools',
|
'idstools',
|
||||||
'suricata.manager',
|
'suricata.manager',
|
||||||
@@ -108,7 +111,8 @@
|
|||||||
'zeek',
|
'zeek',
|
||||||
'schedule',
|
'schedule',
|
||||||
'tcpreplay',
|
'tcpreplay',
|
||||||
'docker_clean'
|
'docker_clean',
|
||||||
|
'learn'
|
||||||
],
|
],
|
||||||
'so-manager': [
|
'so-manager': [
|
||||||
'salt.master',
|
'salt.master',
|
||||||
@@ -121,13 +125,15 @@
|
|||||||
'influxdb',
|
'influxdb',
|
||||||
'grafana',
|
'grafana',
|
||||||
'soc',
|
'soc',
|
||||||
|
'kratos',
|
||||||
'firewall',
|
'firewall',
|
||||||
'idstools',
|
'idstools',
|
||||||
'suricata.manager',
|
'suricata.manager',
|
||||||
'utility',
|
'utility',
|
||||||
'schedule',
|
'schedule',
|
||||||
'soctopus',
|
'soctopus',
|
||||||
'docker_clean'
|
'docker_clean',
|
||||||
|
'learn'
|
||||||
],
|
],
|
||||||
'so-managersearch': [
|
'so-managersearch': [
|
||||||
'salt.master',
|
'salt.master',
|
||||||
@@ -139,6 +145,7 @@
|
|||||||
'influxdb',
|
'influxdb',
|
||||||
'grafana',
|
'grafana',
|
||||||
'soc',
|
'soc',
|
||||||
|
'kratos',
|
||||||
'firewall',
|
'firewall',
|
||||||
'manager',
|
'manager',
|
||||||
'idstools',
|
'idstools',
|
||||||
@@ -146,7 +153,8 @@
|
|||||||
'utility',
|
'utility',
|
||||||
'schedule',
|
'schedule',
|
||||||
'soctopus',
|
'soctopus',
|
||||||
'docker_clean'
|
'docker_clean',
|
||||||
|
'learn'
|
||||||
],
|
],
|
||||||
'so-node': [
|
'so-node': [
|
||||||
'ca',
|
'ca',
|
||||||
@@ -168,6 +176,7 @@
|
|||||||
'influxdb',
|
'influxdb',
|
||||||
'grafana',
|
'grafana',
|
||||||
'soc',
|
'soc',
|
||||||
|
'kratos',
|
||||||
'firewall',
|
'firewall',
|
||||||
'idstools',
|
'idstools',
|
||||||
'suricata.manager',
|
'suricata.manager',
|
||||||
@@ -178,7 +187,8 @@
|
|||||||
'schedule',
|
'schedule',
|
||||||
'soctopus',
|
'soctopus',
|
||||||
'tcpreplay',
|
'tcpreplay',
|
||||||
'docker_clean'
|
'docker_clean',
|
||||||
|
'learn'
|
||||||
],
|
],
|
||||||
'so-sensor': [
|
'so-sensor': [
|
||||||
'ca',
|
'ca',
|
||||||
@@ -233,11 +243,16 @@
|
|||||||
{% do allowed_states.append('elasticsearch') %}
|
{% do allowed_states.append('elasticsearch') %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if KIBANA and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %}
|
{% if ELASTICSEARCH and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %}
|
||||||
{% do allowed_states.append('kibana') %}
|
{% do allowed_states.append('elasticsearch.auth') %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if CURATOR and grains.role in ['so-eval', 'so-standalone', 'so-node', 'so-managersearch', 'so-heavynode'] %}
|
{% if KIBANA and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %}
|
||||||
|
{% do allowed_states.append('kibana') %}
|
||||||
|
{% do allowed_states.append('kibana.secrets') %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if grains.role in ['so-eval', 'so-standalone', 'so-node', 'so-managersearch', 'so-heavynode', 'so-manager'] %}
|
||||||
{% do allowed_states.append('curator') %}
|
{% do allowed_states.append('curator') %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ pki_private_key:
|
|||||||
- x509: /etc/pki/ca.crt
|
- x509: /etc/pki/ca.crt
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
/etc/pki/ca.crt:
|
pki_public_ca_crt:
|
||||||
x509.certificate_managed:
|
x509.certificate_managed:
|
||||||
|
- name: /etc/pki/ca.crt
|
||||||
- signing_private_key: /etc/pki/ca.key
|
- signing_private_key: /etc/pki/ca.key
|
||||||
- CN: {{ manager }}
|
- CN: {{ manager }}
|
||||||
- C: US
|
- C: US
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
/opt/so/log/salt/so-salt-minion-check
|
/opt/so/log/salt/so-salt-minion-check
|
||||||
/opt/so/log/salt/minion
|
/opt/so/log/salt/minion
|
||||||
/opt/so/log/salt/master
|
/opt/so/log/salt/master
|
||||||
|
/opt/so/log/logscan/*.log
|
||||||
{
|
{
|
||||||
{{ logrotate_conf | indent(width=4) }}
|
{{ logrotate_conf | indent(width=4) }}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,18 @@
|
|||||||
{% if sls in allowed_states %}
|
{% if sls in allowed_states %}
|
||||||
|
|
||||||
{% set role = grains.id.split('_') | last %}
|
{% set role = grains.id.split('_') | last %}
|
||||||
|
{% from 'elasticsearch/auth.map.jinja' import ELASTICAUTH with context %}
|
||||||
|
|
||||||
# Remove variables.txt from /tmp - This is temp
|
# Remove variables.txt from /tmp - This is temp
|
||||||
rmvariablesfile:
|
rmvariablesfile:
|
||||||
file.absent:
|
file.absent:
|
||||||
- name: /tmp/variables.txt
|
- name: /tmp/variables.txt
|
||||||
|
|
||||||
|
dockergroup:
|
||||||
|
group.present:
|
||||||
|
- name: docker
|
||||||
|
- gid: 920
|
||||||
|
|
||||||
# Add socore Group
|
# Add socore Group
|
||||||
socoregroup:
|
socoregroup:
|
||||||
group.present:
|
group.present:
|
||||||
@@ -95,22 +101,29 @@ commonpkgs:
|
|||||||
- netcat
|
- netcat
|
||||||
- python3-mysqldb
|
- python3-mysqldb
|
||||||
- sqlite3
|
- sqlite3
|
||||||
- argon2
|
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
- python3-dateutil
|
- python3-dateutil
|
||||||
- python3-m2crypto
|
- python3-m2crypto
|
||||||
- python3-mysqldb
|
- python3-mysqldb
|
||||||
- python3-packaging
|
- python3-packaging
|
||||||
|
- python3-lxml
|
||||||
- git
|
- git
|
||||||
- vim
|
- vim
|
||||||
|
|
||||||
heldpackages:
|
heldpackages:
|
||||||
pkg.installed:
|
pkg.installed:
|
||||||
- pkgs:
|
- pkgs:
|
||||||
|
{% if grains['oscodename'] == 'bionic' %}
|
||||||
- containerd.io: 1.4.4-1
|
- containerd.io: 1.4.4-1
|
||||||
- docker-ce: 5:20.10.5~3-0~ubuntu-bionic
|
- docker-ce: 5:20.10.5~3-0~ubuntu-bionic
|
||||||
- docker-ce-cli: 5:20.10.5~3-0~ubuntu-bionic
|
- docker-ce-cli: 5:20.10.5~3-0~ubuntu-bionic
|
||||||
- docker-ce-rootless-extras: 5:20.10.5~3-0~ubuntu-bionic
|
- docker-ce-rootless-extras: 5:20.10.5~3-0~ubuntu-bionic
|
||||||
|
{% elif grains['oscodename'] == 'focal' %}
|
||||||
|
- containerd.io: 1.4.9-1
|
||||||
|
- docker-ce: 5:20.10.8~3-0~ubuntu-focal
|
||||||
|
- docker-ce-cli: 5:20.10.5~3-0~ubuntu-focal
|
||||||
|
- docker-ce-rootless-extras: 5:20.10.5~3-0~ubuntu-focal
|
||||||
|
{% endif %}
|
||||||
- hold: True
|
- hold: True
|
||||||
- update_holds: True
|
- update_holds: True
|
||||||
|
|
||||||
@@ -128,7 +141,6 @@ commonpkgs:
|
|||||||
- net-tools
|
- net-tools
|
||||||
- curl
|
- curl
|
||||||
- sqlite
|
- sqlite
|
||||||
- argon2
|
|
||||||
- mariadb-devel
|
- mariadb-devel
|
||||||
- nmap-ncat
|
- nmap-ncat
|
||||||
- python3
|
- python3
|
||||||
@@ -137,6 +149,7 @@ commonpkgs:
|
|||||||
- python36-m2crypto
|
- python36-m2crypto
|
||||||
- python36-mysql
|
- python36-mysql
|
||||||
- python36-packaging
|
- python36-packaging
|
||||||
|
- python36-lxml
|
||||||
- yum-utils
|
- yum-utils
|
||||||
- device-mapper-persistent-data
|
- device-mapper-persistent-data
|
||||||
- lvm2
|
- lvm2
|
||||||
@@ -169,6 +182,14 @@ alwaysupdated:
|
|||||||
Etc/UTC:
|
Etc/UTC:
|
||||||
timezone.system
|
timezone.system
|
||||||
|
|
||||||
|
elastic_curl_config:
|
||||||
|
file.managed:
|
||||||
|
- name: /opt/so/conf/elasticsearch/curl.config
|
||||||
|
- source: salt://elasticsearch/curl.config
|
||||||
|
- mode: 600
|
||||||
|
- show_changes: False
|
||||||
|
- makedirs: True
|
||||||
|
|
||||||
# Sync some Utilities
|
# Sync some Utilities
|
||||||
utilsyncscripts:
|
utilsyncscripts:
|
||||||
file.recurse:
|
file.recurse:
|
||||||
@@ -178,6 +199,10 @@ utilsyncscripts:
|
|||||||
- file_mode: 755
|
- file_mode: 755
|
||||||
- template: jinja
|
- template: jinja
|
||||||
- source: salt://common/tools/sbin
|
- source: salt://common/tools/sbin
|
||||||
|
- defaults:
|
||||||
|
ELASTICCURL: 'curl'
|
||||||
|
- context:
|
||||||
|
ELASTICCURL: {{ ELASTICAUTH.elasticcurl }}
|
||||||
|
|
||||||
{% if role in ['eval', 'standalone', 'sensor', 'heavynode'] %}
|
{% if role in ['eval', 'standalone', 'sensor', 'heavynode'] %}
|
||||||
# Add sensor cleanup
|
# Add sensor cleanup
|
||||||
@@ -315,6 +340,16 @@ dockerreserveports:
|
|||||||
- name: /etc/sysctl.d/99-reserved-ports.conf
|
- name: /etc/sysctl.d/99-reserved-ports.conf
|
||||||
|
|
||||||
{% if salt['grains.get']('sosmodel', '') %}
|
{% if salt['grains.get']('sosmodel', '') %}
|
||||||
|
{% if grains['os'] == 'CentOS' %}
|
||||||
|
# Install Raid tools
|
||||||
|
raidpkgs:
|
||||||
|
pkg.installed:
|
||||||
|
- skip_suggestions: True
|
||||||
|
- pkgs:
|
||||||
|
- securityonion-raidtools
|
||||||
|
- securityonion-megactl
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Install raid check cron
|
# Install raid check cron
|
||||||
/usr/sbin/so-raid-status > /dev/null 2>&1:
|
/usr/sbin/so-raid-status > /dev/null 2>&1:
|
||||||
cron.present:
|
cron.present:
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
|
||||||
|
|
||||||
UPDATE_DIR=/tmp/sohotfixapply
|
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo "No tarball given. Please provide the filename so I can run the hotfix"
|
|
||||||
echo "so-airgap-hotfixapply /path/to/sohotfix.tar"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
if [ ! -f "$1" ]; then
|
|
||||||
echo "Unable to find $1. Make sure your path is correct and retry."
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Determining if we need to apply this hotfix"
|
|
||||||
rm -rf $UPDATE_DIR
|
|
||||||
mkdir -p $UPDATE_DIR
|
|
||||||
tar xvf $1 -C $UPDATE_DIR
|
|
||||||
|
|
||||||
# Compare some versions
|
|
||||||
NEWVERSION=$(cat $UPDATE_DIR/VERSION)
|
|
||||||
HOTFIXVERSION=$(cat $UPDATE_DIR/HOTFIX)
|
|
||||||
CURRENTHOTFIX=$(cat /etc/sohotfix)
|
|
||||||
INSTALLEDVERSION=$(cat /etc/soversion)
|
|
||||||
|
|
||||||
if [ "$INSTALLEDVERSION" == "$NEWVERSION" ]; then
|
|
||||||
echo "Checking to see if there are hotfixes needed"
|
|
||||||
if [ "$HOTFIXVERSION" == "$CURRENTHOTFIX" ]; then
|
|
||||||
echo "You are already running the latest version of Security Onion."
|
|
||||||
rm -rf $UPDATE_DIR
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "We need to apply a hotfix"
|
|
||||||
copy_new_files
|
|
||||||
echo $HOTFIXVERSION > /etc/sohotfix
|
|
||||||
salt-call state.highstate -l info queue=True
|
|
||||||
echo "The Hotfix $HOTFIXVERSION has been applied"
|
|
||||||
# Clean up
|
|
||||||
rm -rf $UPDATE_DIR
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "This hotfix is not compatible with your current version. Download the latest ISO and run soup"
|
|
||||||
rm -rf $UPDATE_DIR
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
#
|
#
|
||||||
@@ -15,152 +15,199 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
import ipaddress
|
||||||
|
import textwrap
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
from lxml import etree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
from datetime import datetime as dt
|
||||||
|
from datetime import timezone as tz
|
||||||
|
|
||||||
local_salt_dir=/opt/so/saltstack/local
|
|
||||||
|
|
||||||
SKIP=0
|
|
||||||
|
|
||||||
function usage {
|
|
||||||
|
|
||||||
cat << EOF
|
|
||||||
|
|
||||||
Usage: $0 [-abefhoprsw] [ -i IP ]
|
|
||||||
|
|
||||||
This program allows you to add a firewall rule to allow connections from a new IP address or CIDR range.
|
|
||||||
|
|
||||||
If you run this program with no arguments, it will present a menu for you to choose your options.
|
|
||||||
|
|
||||||
If you want to automate and skip the menu, you can pass the desired options as command line arguments.
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
|
|
||||||
To add 10.1.2.3 to the analyst role:
|
|
||||||
so-allow -a -i 10.1.2.3
|
|
||||||
|
|
||||||
To add 10.1.2.0/24 to the osquery role:
|
|
||||||
so-allow -o -i 10.1.2.0/24
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
|
LOCAL_SALT_DIR='/opt/so/saltstack/local'
|
||||||
|
WAZUH_CONF='/nsm/wazuh/etc/ossec.conf'
|
||||||
|
VALID_ROLES = {
|
||||||
|
'a': { 'role': 'analyst','desc': 'Analyst - 80/tcp, 443/tcp' },
|
||||||
|
'b': { 'role': 'beats_endpoint', 'desc': 'Logstash Beat - 5044/tcp' },
|
||||||
|
'e': { 'role': 'elasticsearch_rest', 'desc': 'Elasticsearch REST API - 9200/tcp' },
|
||||||
|
'f': { 'role': 'strelka_frontend', 'desc': 'Strelka frontend - 57314/tcp' },
|
||||||
|
'o': { 'role': 'osquery_endpoint', 'desc': 'Osquery endpoint - 8090/tcp' },
|
||||||
|
's': { 'role': 'syslog', 'desc': 'Syslog device - 514/tcp/udp' },
|
||||||
|
'w': { 'role': 'wazuh_agent', 'desc': 'Wazuh agent - 1514/tcp/udp' },
|
||||||
|
'p': { 'role': 'wazuh_api', 'desc': 'Wazuh API - 55000/tcp' },
|
||||||
|
'r': { 'role': 'wazuh_authd', 'desc': 'Wazuh registration service - 1515/tcp' }
|
||||||
}
|
}
|
||||||
|
|
||||||
while getopts "ahfesprbowi:" OPTION
|
|
||||||
do
|
|
||||||
case $OPTION in
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
a)
|
|
||||||
FULLROLE="analyst"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
b)
|
|
||||||
FULLROLE="beats_endpoint"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
e)
|
|
||||||
FULLROLE="elasticsearch_rest"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
f)
|
|
||||||
FULLROLE="strelka_frontend"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
i) IP=$OPTARG
|
|
||||||
;;
|
|
||||||
o)
|
|
||||||
FULLROLE="osquery_endpoint"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
w)
|
|
||||||
FULLROLE="wazuh_agent"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
s)
|
|
||||||
FULLROLE="syslog"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
p)
|
|
||||||
FULLROLE="wazuh_api"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
r)
|
|
||||||
FULLROLE="wazuh_authd"
|
|
||||||
SKIP=1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$SKIP" -eq 0 ]; then
|
def validate_ip_cidr(ip_cidr: str) -> bool:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip_cidr)
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_network(ip_cidr)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
echo "This program allows you to add a firewall rule to allow connections from a new IP address."
|
|
||||||
echo ""
|
|
||||||
echo "Choose the role for the IP or Range you would like to add"
|
|
||||||
echo ""
|
|
||||||
echo "[a] - Analyst - ports 80/tcp and 443/tcp"
|
|
||||||
echo "[b] - Logstash Beat - port 5044/tcp"
|
|
||||||
echo "[e] - Elasticsearch REST API - port 9200/tcp"
|
|
||||||
echo "[f] - Strelka frontend - port 57314/tcp"
|
|
||||||
echo "[o] - Osquery endpoint - port 8090/tcp"
|
|
||||||
echo "[s] - Syslog device - 514/tcp/udp"
|
|
||||||
echo "[w] - Wazuh agent - port 1514/tcp/udp"
|
|
||||||
echo "[p] - Wazuh API - port 55000/tcp"
|
|
||||||
echo "[r] - Wazuh registration service - 1515/tcp"
|
|
||||||
echo ""
|
|
||||||
echo "Please enter your selection:"
|
|
||||||
read -r ROLE
|
|
||||||
echo "Enter a single ip address or range to allow (example: 10.10.10.10 or 10.10.0.0/16):"
|
|
||||||
read -r IP
|
|
||||||
|
|
||||||
if [ "$ROLE" == "a" ]; then
|
def role_prompt() -> str:
|
||||||
FULLROLE=analyst
|
print()
|
||||||
elif [ "$ROLE" == "b" ]; then
|
print('Choose the role for the IP or Range you would like to allow')
|
||||||
FULLROLE=beats_endpoint
|
print()
|
||||||
elif [ "$ROLE" == "e" ]; then
|
for role in VALID_ROLES:
|
||||||
FULLROLE=elasticsearch_rest
|
print(f'[{role}] - {VALID_ROLES[role]["desc"]}')
|
||||||
elif [ "$ROLE" == "f" ]; then
|
print()
|
||||||
FULLROLE=strelka_frontend
|
role = input('Please enter your selection: ')
|
||||||
elif [ "$ROLE" == "o" ]; then
|
if role in VALID_ROLES.keys():
|
||||||
FULLROLE=osquery_endpoint
|
return VALID_ROLES[role]['role']
|
||||||
elif [ "$ROLE" == "w" ]; then
|
else:
|
||||||
FULLROLE=wazuh_agent
|
print(f'Invalid role \'{role}\', please try again.', file=sys.stderr)
|
||||||
elif [ "$ROLE" == "s" ]; then
|
sys.exit(1)
|
||||||
FULLROLE=syslog
|
|
||||||
elif [ "$ROLE" == "p" ]; then
|
|
||||||
FULLROLE=wazuh_api
|
|
||||||
elif [ "$ROLE" == "r" ]; then
|
|
||||||
FULLROLE=wazuh_authd
|
|
||||||
else
|
|
||||||
echo "I don't recognize that role"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Adding $IP to the $FULLROLE role. This can take a few seconds"
|
def ip_prompt() -> str:
|
||||||
/usr/sbin/so-firewall includehost $FULLROLE $IP
|
ip = input('Enter a single ip address or range to allow (ex: 10.10.10.10 or 10.10.0.0/16): ')
|
||||||
salt-call state.apply firewall queue=True
|
if validate_ip_cidr(ip):
|
||||||
|
return ip
|
||||||
|
else:
|
||||||
|
print(f'Invalid IP address or CIDR block \'{ip}\', please try again.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def wazuh_enabled() -> bool:
|
||||||
|
for file in os.listdir(f'{LOCAL_SALT_DIR}/pillar'):
|
||||||
|
with open(file, 'r') as pillar:
|
||||||
|
if 'wazuh: 1' in pillar.read():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def root_to_str(root: ET.ElementTree) -> str:
|
||||||
|
xml_str = ET.tostring(root, encoding='unicode', method='xml').replace('\n', '')
|
||||||
|
xml_str = re.sub(r'(?:(?<=>) *)', '', xml_str)
|
||||||
|
xml_str = re.sub(r' -', '', xml_str)
|
||||||
|
xml_str = re.sub(r' -->', ' -->', xml_str)
|
||||||
|
dom = minidom.parseString(xml_str)
|
||||||
|
return dom.toprettyxml(indent=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def add_wl(ip):
|
||||||
|
parser = ET.XMLParser(remove_blank_text=True)
|
||||||
|
with open(WAZUH_CONF, 'rb') as wazuh_conf:
|
||||||
|
tree = ET.parse(wazuh_conf, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
source_comment = ET.Comment(f'Address {ip} added by /usr/sbin/so-allow on {dt.utcnow().replace(tzinfo=tz.utc).strftime("%a %b %e %H:%M:%S %Z %Y")}')
|
||||||
|
new_global = ET.Element("global")
|
||||||
|
new_wl = ET.SubElement(new_global, 'white_list')
|
||||||
|
new_wl.text = ip
|
||||||
|
|
||||||
|
root.append(source_comment)
|
||||||
|
root.append(new_global)
|
||||||
|
|
||||||
|
with open(WAZUH_CONF, 'w') as add_out:
|
||||||
|
add_out.write(root_to_str(root))
|
||||||
|
|
||||||
|
|
||||||
|
def apply(role: str, ip: str) -> int:
|
||||||
|
firewall_cmd = ['so-firewall', 'includehost', role, ip]
|
||||||
|
salt_cmd = ['salt-call', 'state.apply', '-l', 'quiet', 'firewall', 'queue=True']
|
||||||
|
restart_wazuh_cmd = ['so-wazuh-restart']
|
||||||
|
print(f'Adding {ip} to the {role} role. This can take a few seconds...')
|
||||||
|
cmd = subprocess.run(firewall_cmd)
|
||||||
|
if cmd.returncode == 0:
|
||||||
|
cmd = subprocess.run(salt_cmd, stdout=subprocess.DEVNULL)
|
||||||
|
else:
|
||||||
|
return cmd.returncode
|
||||||
|
if cmd.returncode == 0:
|
||||||
|
if wazuh_enabled and role=='analyst':
|
||||||
|
try:
|
||||||
|
add_wl(ip)
|
||||||
|
print(f'Added whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Failed to add whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||||
|
print(e)
|
||||||
|
return 1
|
||||||
|
print('Restarting OSSEC Server...')
|
||||||
|
cmd = subprocess.run(restart_wazuh_cmd)
|
||||||
|
else:
|
||||||
|
return cmd.returncode
|
||||||
|
else:
|
||||||
|
print(f'Commmand \'{" ".join(salt_cmd)}\' failed.', file=sys.stderr)
|
||||||
|
return cmd.returncode
|
||||||
|
if cmd.returncode != 0:
|
||||||
|
print('Failed to restart OSSEC server.')
|
||||||
|
return cmd.returncode
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print('You must run this script as root', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main_parser = argparse.ArgumentParser(
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog=textwrap.dedent(f'''\
|
||||||
|
additional information:
|
||||||
|
To use this script in interactive mode call it with no arguments
|
||||||
|
'''
|
||||||
|
))
|
||||||
|
|
||||||
|
group = main_parser.add_argument_group(title='roles')
|
||||||
|
group.add_argument('-a', dest='roles', action='append_const', const=VALID_ROLES['a']['role'], help="Analyst - 80/tcp, 443/tcp")
|
||||||
|
group.add_argument('-b', dest='roles', action='append_const', const=VALID_ROLES['b']['role'], help="Logstash Beat - 5044/tcp")
|
||||||
|
group.add_argument('-e', dest='roles', action='append_const', const=VALID_ROLES['e']['role'], help="Elasticsearch REST API - 9200/tcp")
|
||||||
|
group.add_argument('-f', dest='roles', action='append_const', const=VALID_ROLES['f']['role'], help="Strelka frontend - 57314/tcp")
|
||||||
|
group.add_argument('-o', dest='roles', action='append_const', const=VALID_ROLES['o']['role'], help="Osquery endpoint - 8090/tcp")
|
||||||
|
group.add_argument('-s', dest='roles', action='append_const', const=VALID_ROLES['s']['role'], help="Syslog device - 514/tcp/udp")
|
||||||
|
group.add_argument('-w', dest='roles', action='append_const', const=VALID_ROLES['w']['role'], help="Wazuh agent - 1514/tcp/udp")
|
||||||
|
group.add_argument('-p', dest='roles', action='append_const', const=VALID_ROLES['p']['role'], help="Wazuh API - 55000/tcp")
|
||||||
|
group.add_argument('-r', dest='roles', action='append_const', const=VALID_ROLES['r']['role'], help="Wazuh registration service - 1515/tcp")
|
||||||
|
|
||||||
|
ip_g = main_parser.add_argument_group(title='allow')
|
||||||
|
ip_g.add_argument('-i', help="IP or CIDR block to disallow connections from, requires at least one role argument", metavar='', dest='ip')
|
||||||
|
|
||||||
|
args = main_parser.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
if args.roles is None:
|
||||||
|
role = role_prompt()
|
||||||
|
ip = ip_prompt()
|
||||||
|
try:
|
||||||
|
return_code = apply(role, ip)
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||||
|
return_code = e.errno
|
||||||
|
sys.exit(return_code)
|
||||||
|
elif args.roles is not None and args.ip is None:
|
||||||
|
if os.environ.get('IP') is None:
|
||||||
|
main_parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
args.ip = os.environ['IP']
|
||||||
|
|
||||||
|
if validate_ip_cidr(args.ip):
|
||||||
|
try:
|
||||||
|
for role in args.roles:
|
||||||
|
return_code = apply(role, args.ip)
|
||||||
|
if return_code > 0:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||||
|
return_code = e.errno
|
||||||
|
else:
|
||||||
|
print(f'Invalid IP address or CIDR block \'{args.ip}\', please try again.', file=sys.stderr)
|
||||||
|
return_code = 1
|
||||||
|
|
||||||
|
sys.exit(return_code)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Check if Wazuh enabled
|
|
||||||
if grep -q -R "wazuh: 1" $local_salt_dir/pillar/*; then
|
|
||||||
# If analyst, add to Wazuh AR whitelist
|
|
||||||
if [ "$FULLROLE" == "analyst" ]; then
|
|
||||||
WAZUH_MGR_CFG="/nsm/wazuh/etc/ossec.conf"
|
|
||||||
if ! grep -q "<white_list>$IP</white_list>" $WAZUH_MGR_CFG ; then
|
|
||||||
DATE=$(date)
|
|
||||||
sed -i 's/<\/ossec_config>//' $WAZUH_MGR_CFG
|
|
||||||
sed -i '/^$/N;/^\n$/D' $WAZUH_MGR_CFG
|
|
||||||
echo -e "<!--Address $IP added by /usr/sbin/so-allow on \"$DATE\"-->\n <global>\n <white_list>$IP</white_list>\n </global>\n</ossec_config>" >> $WAZUH_MGR_CFG
|
|
||||||
echo "Added whitelist entry for $IP in $WAZUH_MGR_CFG."
|
|
||||||
echo
|
|
||||||
echo "Restarting OSSEC Server..."
|
|
||||||
/usr/sbin/so-wazuh-restart
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -17,4 +17,4 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
salt-call state.highstate
|
salt-call state.highstate -l info
|
||||||
|
|||||||
@@ -88,19 +88,6 @@ add_interface_bond0() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_airgap() {
|
|
||||||
# See if this is an airgap install
|
|
||||||
AIRGAP=$(cat /opt/so/saltstack/local/pillar/global.sls | grep airgap: | awk '{print $2}')
|
|
||||||
if [[ "$AIRGAP" == "True" ]]; then
|
|
||||||
is_airgap=0
|
|
||||||
UPDATE_DIR=/tmp/soagupdate/SecurityOnion
|
|
||||||
AGDOCKER=/tmp/soagupdate/docker
|
|
||||||
AGREPO=/tmp/soagupdate/Packages
|
|
||||||
else
|
|
||||||
is_airgap=1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_container() {
|
check_container() {
|
||||||
docker ps | grep "$1:" > /dev/null 2>&1
|
docker ps | grep "$1:" > /dev/null 2>&1
|
||||||
return $?
|
return $?
|
||||||
@@ -112,6 +99,15 @@ check_password() {
|
|||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_password_and_exit() {
|
||||||
|
local password=$1
|
||||||
|
if ! check_password "$password"; then
|
||||||
|
echo "Password is invalid. Do not include single quotes, double quotes, dollar signs, and backslashes in the password."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
check_elastic_license() {
|
check_elastic_license() {
|
||||||
|
|
||||||
[ -n "$TESTING" ] && return
|
[ -n "$TESTING" ] && return
|
||||||
@@ -153,7 +149,7 @@ Do you agree to the terms of the Elastic License?
|
|||||||
If so, type AGREE to accept the Elastic License and continue. Otherwise, press Enter to exit this program without making any changes.
|
If so, type AGREE to accept the Elastic License and continue. Otherwise, press Enter to exit this program without making any changes.
|
||||||
EOM
|
EOM
|
||||||
|
|
||||||
AGREED=$(whiptail --title "Security Onion Setup" --inputbox \
|
AGREED=$(whiptail --title "$whiptail_title" --inputbox \
|
||||||
"$message" 20 75 3>&1 1>&2 2>&3)
|
"$message" 20 75 3>&1 1>&2 2>&3)
|
||||||
|
|
||||||
if [ "${AGREED^^}" = 'AGREE' ]; then
|
if [ "${AGREED^^}" = 'AGREE' ]; then
|
||||||
@@ -252,6 +248,7 @@ lookup_salt_value() {
|
|||||||
key=$1
|
key=$1
|
||||||
group=$2
|
group=$2
|
||||||
kind=$3
|
kind=$3
|
||||||
|
output=${4:-newline_values_only}
|
||||||
|
|
||||||
if [ -z "$kind" ]; then
|
if [ -z "$kind" ]; then
|
||||||
kind=pillar
|
kind=pillar
|
||||||
@@ -261,7 +258,7 @@ lookup_salt_value() {
|
|||||||
group=${group}:
|
group=${group}:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
salt-call --no-color ${kind}.get ${group}${key} --out=newline_values_only
|
salt-call --no-color ${kind}.get ${group}${key} --out=${output}
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup_pillar() {
|
lookup_pillar() {
|
||||||
@@ -289,7 +286,7 @@ lookup_role() {
|
|||||||
|
|
||||||
require_manager() {
|
require_manager() {
|
||||||
if is_manager_node; then
|
if is_manager_node; then
|
||||||
echo "This is a manager, We can proceed."
|
echo "This is a manager, so we can proceed."
|
||||||
else
|
else
|
||||||
echo "Please run this command on the manager; the manager controls the grid."
|
echo "Please run this command on the manager; the manager controls the grid."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -302,6 +299,7 @@ retry() {
|
|||||||
cmd=$3
|
cmd=$3
|
||||||
expectedOutput=$4
|
expectedOutput=$4
|
||||||
attempt=0
|
attempt=0
|
||||||
|
local exitcode=0
|
||||||
while [[ $attempt -lt $maxAttempts ]]; do
|
while [[ $attempt -lt $maxAttempts ]]; do
|
||||||
attempt=$((attempt+1))
|
attempt=$((attempt+1))
|
||||||
echo "Executing command with retry support: $cmd"
|
echo "Executing command with retry support: $cmd"
|
||||||
@@ -321,7 +319,29 @@ retry() {
|
|||||||
sleep $sleepDelay
|
sleep $sleepDelay
|
||||||
done
|
done
|
||||||
echo "Command continues to fail; giving up."
|
echo "Command continues to fail; giving up."
|
||||||
return 1
|
return $exitcode
|
||||||
|
}
|
||||||
|
|
||||||
|
run_check_net_err() {
|
||||||
|
local cmd=$1
|
||||||
|
local err_msg=${2:-"Unknown error occured, please check /root/$WHATWOULDYOUSAYYAHDOHERE.log for details."} # Really need to rename that variable
|
||||||
|
local no_retry=$3
|
||||||
|
|
||||||
|
local exit_code
|
||||||
|
if [[ -z $no_retry ]]; then
|
||||||
|
retry 5 60 "$cmd"
|
||||||
|
exit_code=$?
|
||||||
|
else
|
||||||
|
eval "$cmd"
|
||||||
|
exit_code=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
|
ERR_HANDLED=true
|
||||||
|
[[ -z $no_retry ]] || echo "Command failed with error $exit_code"
|
||||||
|
echo "$err_msg"
|
||||||
|
exit $exit_code
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
set_os() {
|
set_os() {
|
||||||
@@ -361,18 +381,29 @@ set_version() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
has_uppercase() {
|
||||||
|
local string=$1
|
||||||
|
|
||||||
|
echo "$string" | grep -qP '[A-Z]' \
|
||||||
|
&& return 0 \
|
||||||
|
|| return 1
|
||||||
|
}
|
||||||
|
|
||||||
valid_cidr() {
|
valid_cidr() {
|
||||||
# Verify there is a backslash in the string
|
# Verify there is a backslash in the string
|
||||||
echo "$1" | grep -qP "^[^/]+/[^/]+$" || return 1
|
echo "$1" | grep -qP "^[^/]+/[^/]+$" || return 1
|
||||||
|
|
||||||
local cidr
|
valid_ip4_cidr_mask "$1" && return 0 || return 1
|
||||||
local ip
|
|
||||||
|
|
||||||
cidr=$(echo "$1" | sed 's/.*\///')
|
local cidr="$1"
|
||||||
ip=$(echo "$1" | sed 's/\/.*//' )
|
local ip
|
||||||
|
ip=$(echo "$cidr" | sed 's/\/.*//' )
|
||||||
|
|
||||||
if valid_ip4 "$ip"; then
|
if valid_ip4 "$ip"; then
|
||||||
[[ $cidr =~ ([0-9]|[1-2][0-9]|3[0-2]) ]] && return 0 || return 1
|
local ip1 ip2 ip3 ip4 N
|
||||||
|
IFS="./" read -r ip1 ip2 ip3 ip4 N <<< "$cidr"
|
||||||
|
ip_total=$((ip1 * 256 ** 3 + ip2 * 256 ** 2 + ip3 * 256 + ip4))
|
||||||
|
[[ $((ip_total % 2**(32-N))) == 0 ]] && return 0 || return 1
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -422,6 +453,23 @@ valid_ip4() {
|
|||||||
echo "$ip" | grep -qP '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' && return 0 || return 1
|
echo "$ip" | grep -qP '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' && return 0 || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valid_ip4_cidr_mask() {
|
||||||
|
# Verify there is a backslash in the string
|
||||||
|
echo "$1" | grep -qP "^[^/]+/[^/]+$" || return 1
|
||||||
|
|
||||||
|
local cidr
|
||||||
|
local ip
|
||||||
|
|
||||||
|
cidr=$(echo "$1" | sed 's/.*\///')
|
||||||
|
ip=$(echo "$1" | sed 's/\/.*//' )
|
||||||
|
|
||||||
|
if valid_ip4 "$ip"; then
|
||||||
|
[[ $cidr =~ ^([0-9]|[1-2][0-9]|3[0-2])$ ]] && return 0 || return 1
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
valid_int() {
|
valid_int() {
|
||||||
local num=$1
|
local num=$1
|
||||||
local min=${2:-1}
|
local min=${2:-1}
|
||||||
@@ -486,13 +534,14 @@ wait_for_web_response() {
|
|||||||
url=$1
|
url=$1
|
||||||
expected=$2
|
expected=$2
|
||||||
maxAttempts=${3:-300}
|
maxAttempts=${3:-300}
|
||||||
|
curlcmd=${4:-curl}
|
||||||
logfile=/root/wait_for_web_response.log
|
logfile=/root/wait_for_web_response.log
|
||||||
truncate -s 0 "$logfile"
|
truncate -s 0 "$logfile"
|
||||||
attempt=0
|
attempt=0
|
||||||
while [[ $attempt -lt $maxAttempts ]]; do
|
while [[ $attempt -lt $maxAttempts ]]; do
|
||||||
attempt=$((attempt+1))
|
attempt=$((attempt+1))
|
||||||
echo "Waiting for value '$expected' at '$url' ($attempt/$maxAttempts)"
|
echo "Waiting for value '$expected' at '$url' ($attempt/$maxAttempts)"
|
||||||
result=$(curl -ks -L $url)
|
result=$($curlcmd -ks -L $url)
|
||||||
exitcode=$?
|
exitcode=$?
|
||||||
|
|
||||||
echo "--------------------------------------------------" >> $logfile
|
echo "--------------------------------------------------" >> $logfile
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ if [ ! -f $BACKUPFILE ]; then
|
|||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
tar -rf $BACKUPFILE /etc/pki
|
tar -rf $BACKUPFILE /etc/pki
|
||||||
tar -rf $BACKUPFILE /etc/salt
|
tar -rf $BACKUPFILE /etc/salt
|
||||||
|
tar -rf $BACKUPFILE /opt/so/conf/kratos
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
213
salt/common/tools/sbin/so-deny
Executable file
213
salt/common/tools/sbin/so-deny
Executable file
@@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
|
import textwrap
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
from lxml import etree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL_SALT_DIR='/opt/so/saltstack/local'
|
||||||
|
WAZUH_CONF='/nsm/wazuh/etc/ossec.conf'
|
||||||
|
VALID_ROLES = {
|
||||||
|
'a': { 'role': 'analyst','desc': 'Analyst - 80/tcp, 443/tcp' },
|
||||||
|
'b': { 'role': 'beats_endpoint', 'desc': 'Logstash Beat - 5044/tcp' },
|
||||||
|
'e': { 'role': 'elasticsearch_rest', 'desc': 'Elasticsearch REST API - 9200/tcp' },
|
||||||
|
'f': { 'role': 'strelka_frontend', 'desc': 'Strelka frontend - 57314/tcp' },
|
||||||
|
'o': { 'role': 'osquery_endpoint', 'desc': 'Osquery endpoint - 8090/tcp' },
|
||||||
|
's': { 'role': 'syslog', 'desc': 'Syslog device - 514/tcp/udp' },
|
||||||
|
'w': { 'role': 'wazuh_agent', 'desc': 'Wazuh agent - 1514/tcp/udp' },
|
||||||
|
'p': { 'role': 'wazuh_api', 'desc': 'Wazuh API - 55000/tcp' },
|
||||||
|
'r': { 'role': 'wazuh_authd', 'desc': 'Wazuh registration service - 1515/tcp' }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_ip_cidr(ip_cidr: str) -> bool:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip_cidr)
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_network(ip_cidr)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def role_prompt() -> str:
|
||||||
|
print()
|
||||||
|
print('Choose the role for the IP or Range you would like to deny')
|
||||||
|
print()
|
||||||
|
for role in VALID_ROLES:
|
||||||
|
print(f'[{role}] - {VALID_ROLES[role]["desc"]}')
|
||||||
|
print()
|
||||||
|
role = input('Please enter your selection: ')
|
||||||
|
if role in VALID_ROLES.keys():
|
||||||
|
return VALID_ROLES[role]['role']
|
||||||
|
else:
|
||||||
|
print(f'Invalid role \'{role}\', please try again.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def ip_prompt() -> str:
|
||||||
|
ip = input('Enter a single ip address or range to deny (ex: 10.10.10.10 or 10.10.0.0/16): ')
|
||||||
|
if validate_ip_cidr(ip):
|
||||||
|
return ip
|
||||||
|
else:
|
||||||
|
print(f'Invalid IP address or CIDR block \'{ip}\', please try again.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def wazuh_enabled() -> bool:
|
||||||
|
for file in os.listdir(f'{LOCAL_SALT_DIR}/pillar'):
|
||||||
|
with open(file, 'r') as pillar:
|
||||||
|
if 'wazuh: 1' in pillar.read():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def root_to_str(root: ET.ElementTree) -> str:
|
||||||
|
xml_str = ET.tostring(root, encoding='unicode', method='xml').replace('\n', '')
|
||||||
|
xml_str = re.sub(r'(?:(?<=>) *)', '', xml_str)
|
||||||
|
|
||||||
|
# Remove specific substrings to better format comments on intial parse/write
|
||||||
|
xml_str = re.sub(r' -', '', xml_str)
|
||||||
|
xml_str = re.sub(r' -->', ' -->', xml_str)
|
||||||
|
|
||||||
|
dom = minidom.parseString(xml_str)
|
||||||
|
return dom.toprettyxml(indent=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def rem_wl(ip):
|
||||||
|
parser = ET.XMLParser(remove_blank_text=True)
|
||||||
|
with open(WAZUH_CONF, 'rb') as wazuh_conf:
|
||||||
|
tree = ET.parse(wazuh_conf, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
global_elems = root.findall(f"global/white_list[. = '{ip}']/..")
|
||||||
|
if len(global_elems) > 0:
|
||||||
|
for g_elem in global_elems:
|
||||||
|
ge_index = list(root).index(g_elem)
|
||||||
|
if ge_index > 0 and root[list(root).index(g_elem) - 1].tag == ET.Comment:
|
||||||
|
root.remove(root[ge_index - 1])
|
||||||
|
root.remove(g_elem)
|
||||||
|
|
||||||
|
with open(WAZUH_CONF, 'w') as out:
|
||||||
|
out.write(root_to_str(root))
|
||||||
|
|
||||||
|
|
||||||
|
def apply(role: str, ip: str) -> int:
|
||||||
|
firewall_cmd = ['so-firewall', 'excludehost', role, ip]
|
||||||
|
salt_cmd = ['salt-call', 'state.apply', '-l', 'quiet', 'firewall', 'queue=True']
|
||||||
|
restart_wazuh_cmd = ['so-wazuh-restart']
|
||||||
|
print(f'Removing {ip} from the {role} role. This can take a few seconds...')
|
||||||
|
cmd = subprocess.run(firewall_cmd)
|
||||||
|
if cmd.returncode == 0:
|
||||||
|
cmd = subprocess.run(salt_cmd, stdout=subprocess.DEVNULL)
|
||||||
|
else:
|
||||||
|
return cmd.returncode
|
||||||
|
if cmd.returncode == 0:
|
||||||
|
if wazuh_enabled and role=='analyst':
|
||||||
|
try:
|
||||||
|
rem_wl(ip)
|
||||||
|
print(f'Removed whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Failed to remove whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||||
|
print(e)
|
||||||
|
return 1
|
||||||
|
print('Restarting OSSEC Server...')
|
||||||
|
cmd = subprocess.run(restart_wazuh_cmd)
|
||||||
|
else:
|
||||||
|
return cmd.returncode
|
||||||
|
else:
|
||||||
|
print(f'Commmand \'{" ".join(salt_cmd)}\' failed.', file=sys.stderr)
|
||||||
|
return cmd.returncode
|
||||||
|
if cmd.returncode != 0:
|
||||||
|
print('Failed to restart OSSEC server.')
|
||||||
|
return cmd.returncode
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print('You must run this script as root', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main_parser = argparse.ArgumentParser(
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog=textwrap.dedent(f'''\
|
||||||
|
additional information:
|
||||||
|
To use this script in interactive mode call it with no arguments
|
||||||
|
'''
|
||||||
|
))
|
||||||
|
|
||||||
|
group = main_parser.add_argument_group(title='roles')
|
||||||
|
group.add_argument('-a', dest='roles', action='append_const', const=VALID_ROLES['a']['role'], help="Analyst - 80/tcp, 443/tcp")
|
||||||
|
group.add_argument('-b', dest='roles', action='append_const', const=VALID_ROLES['b']['role'], help="Logstash Beat - 5044/tcp")
|
||||||
|
group.add_argument('-e', dest='roles', action='append_const', const=VALID_ROLES['e']['role'], help="Elasticsearch REST API - 9200/tcp")
|
||||||
|
group.add_argument('-f', dest='roles', action='append_const', const=VALID_ROLES['f']['role'], help="Strelka frontend - 57314/tcp")
|
||||||
|
group.add_argument('-o', dest='roles', action='append_const', const=VALID_ROLES['o']['role'], help="Osquery endpoint - 8090/tcp")
|
||||||
|
group.add_argument('-s', dest='roles', action='append_const', const=VALID_ROLES['s']['role'], help="Syslog device - 514/tcp/udp")
|
||||||
|
group.add_argument('-w', dest='roles', action='append_const', const=VALID_ROLES['w']['role'], help="Wazuh agent - 1514/tcp/udp")
|
||||||
|
group.add_argument('-p', dest='roles', action='append_const', const=VALID_ROLES['p']['role'], help="Wazuh API - 55000/tcp")
|
||||||
|
group.add_argument('-r', dest='roles', action='append_const', const=VALID_ROLES['r']['role'], help="Wazuh registration service - 1515/tcp")
|
||||||
|
|
||||||
|
ip_g = main_parser.add_argument_group(title='allow')
|
||||||
|
ip_g.add_argument('-i', help="IP or CIDR block to disallow connections from, requires at least one role argument", metavar='', dest='ip')
|
||||||
|
|
||||||
|
args = main_parser.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
if args.roles is None:
|
||||||
|
role = role_prompt()
|
||||||
|
ip = ip_prompt()
|
||||||
|
try:
|
||||||
|
return_code = apply(role, ip)
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||||
|
return_code = e.errno
|
||||||
|
sys.exit(return_code)
|
||||||
|
elif args.roles is not None and args.ip is None:
|
||||||
|
if os.environ.get('IP') is None:
|
||||||
|
main_parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
args.ip = os.environ['IP']
|
||||||
|
|
||||||
|
if validate_ip_cidr(args.ip):
|
||||||
|
try:
|
||||||
|
for role in args.roles:
|
||||||
|
return_code = apply(role, args.ip)
|
||||||
|
if return_code > 0:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||||
|
return_code = e.errno
|
||||||
|
else:
|
||||||
|
print(f'Invalid IP address or CIDR block \'{args.ip}\', please try again.', file=sys.stderr)
|
||||||
|
return_code = 1
|
||||||
|
|
||||||
|
sys.exit(return_code)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
@@ -32,19 +32,25 @@ def get_image_version(string) -> str:
|
|||||||
ver = string.split(':')[-1]
|
ver = string.split(':')[-1]
|
||||||
if ver == 'latest':
|
if ver == 'latest':
|
||||||
# Version doesn't like "latest", so use a high semver
|
# Version doesn't like "latest", so use a high semver
|
||||||
return '999999.9.9'
|
return '99999.9.9'
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
Version(ver)
|
Version(ver)
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
# Strip the last substring following a hyphen for automated branches
|
# Also return a very high semver for any version
|
||||||
ver = '-'.join(ver.split('-')[:-1])
|
# with a dash in it since it will likely be a dev version of some kind
|
||||||
|
if '-' in ver:
|
||||||
|
return '999999.9.9'
|
||||||
return ver
|
return ver
|
||||||
|
|
||||||
|
|
||||||
def main(quiet):
|
def main(quiet):
|
||||||
client = docker.from_env()
|
client = docker.from_env()
|
||||||
|
|
||||||
|
# Prune old/stopped containers
|
||||||
|
if not quiet: print('Pruning old containers')
|
||||||
|
client.containers.prune()
|
||||||
|
|
||||||
image_list = client.images.list(filters={ 'dangling': False })
|
image_list = client.images.list(filters={ 'dangling': False })
|
||||||
|
|
||||||
# Map list of image objects to flattened list of tags (format: "name:version")
|
# Map list of image objects to flattened list of tags (format: "name:version")
|
||||||
@@ -72,9 +78,16 @@ def main(quiet):
|
|||||||
for group in grouped_t_list[2:]:
|
for group in grouped_t_list[2:]:
|
||||||
for tag in group:
|
for tag in group:
|
||||||
if not quiet: print(f'Removing image {tag}')
|
if not quiet: print(f'Removing image {tag}')
|
||||||
client.images.remove(tag)
|
try:
|
||||||
except InvalidVersion as e:
|
client.images.remove(tag, force=True)
|
||||||
print(f'so-{get_so_image_basename(t_list[0])}: {e.args[0]}', file=sys.stderr)
|
except docker.errors.ClientError as e:
|
||||||
|
print(f'Could not remove image {tag}, continuing...')
|
||||||
|
except (docker.errors.APIError, InvalidVersion) as e:
|
||||||
|
print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr)
|
||||||
|
exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print('Unhandled exception occurred:')
|
||||||
|
print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if no_prunable and not quiet:
|
if no_prunable and not quiet:
|
||||||
|
|||||||
@@ -145,9 +145,9 @@ EOF
|
|||||||
rulename=$(echo ${raw_rulename,,} | sed 's/ /_/g')
|
rulename=$(echo ${raw_rulename,,} | sed 's/ /_/g')
|
||||||
|
|
||||||
cat << EOF >> "$rulename.yaml"
|
cat << EOF >> "$rulename.yaml"
|
||||||
# Elasticsearch Host
|
# Elasticsearch Host Override (optional)
|
||||||
es_host: elasticsearch
|
# es_host: elasticsearch
|
||||||
es_port: 9200
|
# es_port: 9200
|
||||||
|
|
||||||
# (Required)
|
# (Required)
|
||||||
# Rule name, must be unique
|
# Rule name, must be unique
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ do
|
|||||||
done
|
done
|
||||||
|
|
||||||
docker_exec(){
|
docker_exec(){
|
||||||
CMD="docker exec -it so-elastalert elastalert-test-rule /opt/elastalert/rules/$RULE_NAME --config /opt/config/elastalert_config.yaml $OPTIONS"
|
CMD="docker exec -it so-elastalert elastalert-test-rule /opt/elastalert/rules/$RULE_NAME --config /opt/elastalert/config.yaml $OPTIONS"
|
||||||
if [ "${RESULTS_TO_LOG,,}" = "y" ] ; then
|
if [ "${RESULTS_TO_LOG,,}" = "y" ] ; then
|
||||||
$CMD > "$FILE_SAVE_LOCATION"
|
$CMD > "$FILE_SAVE_LOCATION"
|
||||||
else
|
else
|
||||||
|
|||||||
67
salt/common/tools/sbin/so-elastic-auth
Executable file
67
salt/common/tools/sbin/so-elastic-auth
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
if [ -f "/usr/sbin/so-common" ]; then
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
fi
|
||||||
|
|
||||||
|
ES_AUTH_PILLAR=${ELASTIC_AUTH_PILLAR:-/opt/so/saltstack/local/pillar/elasticsearch/auth.sls}
|
||||||
|
ES_USERS_FILE=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users}
|
||||||
|
|
||||||
|
authEnable=$1
|
||||||
|
|
||||||
|
if ! grep -q "enabled: " "$ES_AUTH_PILLAR"; then
|
||||||
|
echo "Elastic auth pillar file is invalid. Unable to proceed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function restart() {
|
||||||
|
if [[ -z "$ELASTIC_AUTH_SKIP_HIGHSTATE" ]]; then
|
||||||
|
echo "Elasticsearch on all affected minions will now be stopped and then restarted..."
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' cmd.run so-elastic-stop queue=True
|
||||||
|
echo "Applying highstate to all affected minions..."
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' state.highstate queue=True
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$authEnable" == "true" ]]; then
|
||||||
|
if grep -q "enabled: False" "$ES_AUTH_PILLAR"; then
|
||||||
|
sed -i 's/enabled: False/enabled: True/g' "$ES_AUTH_PILLAR"
|
||||||
|
restart
|
||||||
|
echo "Elastic auth is now enabled."
|
||||||
|
if grep -q "argon" "$ES_USERS_FILE"; then
|
||||||
|
echo ""
|
||||||
|
echo "IMPORTANT: The following users will need to change their password, after logging into SOC, in order to access Kibana:"
|
||||||
|
grep argon "$ES_USERS_FILE" | cut -d ":" -f 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Auth is already enabled."
|
||||||
|
fi
|
||||||
|
elif [[ "$authEnable" == "false" ]]; then
|
||||||
|
if grep -q "enabled: True" "$ES_AUTH_PILLAR"; then
|
||||||
|
sed -i 's/enabled: True/enabled: False/g' "$ES_AUTH_PILLAR"
|
||||||
|
restart
|
||||||
|
echo "Elastic auth is now disabled."
|
||||||
|
else
|
||||||
|
echo "Auth is already disabled."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Usage: $0 <true|false>"
|
||||||
|
echo ""
|
||||||
|
echo "Toggles Elastic authentication. Elasticsearch will be restarted on each affected minion."
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
155
salt/common/tools/sbin/so-elastic-auth-password-reset
Normal file
155
salt/common/tools/sbin/so-elastic-auth-password-reset
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
source $(dirname $0)/so-common
|
||||||
|
require_manager
|
||||||
|
|
||||||
|
user=$1
|
||||||
|
elasticUsersFile=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users}
|
||||||
|
elasticAuthPillarFile=${ELASTIC_AUTH_PILLAR_FILE:-/opt/so/saltstack/local/pillar/elasticsearch/auth.sls}
|
||||||
|
|
||||||
|
if [[ $# -ne 1 ]]; then
|
||||||
|
echo "Usage: $0 <user>"
|
||||||
|
echo ""
|
||||||
|
echo " where <user> is one of the following:"
|
||||||
|
echo ""
|
||||||
|
echo " all: Reset the password for the so_elastic, so_kibana, so_logstash, so_beats, and so_monitor users"
|
||||||
|
echo " so_elastic: Reset the password for the so_elastic user"
|
||||||
|
echo " so_kibana: Reset the password for the so_kibana user"
|
||||||
|
echo " so_logstash: Reset the password for the so_logstash user"
|
||||||
|
echo " so_beats: Reset the password for the so_beats user"
|
||||||
|
echo " so_monitor: Reset the password for the so_monitor user"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# function to create a lock so that the so-user sync cronjob can't run while this is running
|
||||||
|
function lock() {
|
||||||
|
# Obtain file descriptor lock
|
||||||
|
exec 99>/var/tmp/so-user.lock || fail "Unable to create lock descriptor; if the system was not shutdown gracefully you may need to remove /var/tmp/so-user.lock manually."
|
||||||
|
flock -w 10 99 || fail "Another process is using so-user; if the system was not shutdown gracefully you may need to remove /var/tmp/so-user.lock manually."
|
||||||
|
trap 'rm -f /var/tmp/so-user.lock' EXIT
|
||||||
|
}
|
||||||
|
|
||||||
|
function unlock() {
|
||||||
|
rm -f /var/tmp/so-user.lock
|
||||||
|
}
|
||||||
|
|
||||||
|
function fail() {
|
||||||
|
msg=$1
|
||||||
|
echo "$1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSingleUserPass() {
|
||||||
|
local user=$1
|
||||||
|
sed -i '/user: '"${user}"'/{N;/pass: /d}' "${elasticAuthPillarFile}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeAllUserPass() {
|
||||||
|
local userList=("so_elastic" "so_kibana" "so_logstash" "so_beats" "so_monitor")
|
||||||
|
|
||||||
|
for u in ${userList[@]}; do
|
||||||
|
removeSingleUserPass "$u"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeElasticUsersFile() {
|
||||||
|
rm -f "$elasticUsersFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
function createElasticAuthPillar() {
|
||||||
|
salt-call state.apply elasticsearch.auth queue=True
|
||||||
|
}
|
||||||
|
|
||||||
|
# this will disable highstate to prevent a highstate from starting while the script is running
|
||||||
|
# will also disable salt.minion-state-apply-test allow so-salt-minion-check cronjob to restart salt-minion service incase
|
||||||
|
function disableSaltStates() {
|
||||||
|
printf "\nDisabling salt.minion-state-apply-test and highstate from running.\n\n"
|
||||||
|
salt-call state.disable salt.minion-state-apply-test
|
||||||
|
salt-call state.disable highstate
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableSaltStates() {
|
||||||
|
printf "\nEnabling salt.minion-state-apply-test and highstate.\n\n"
|
||||||
|
salt-call state.enable salt.minion-state-apply-test
|
||||||
|
salt-call state.enable highstate
|
||||||
|
}
|
||||||
|
|
||||||
|
function killAllSaltJobs() {
|
||||||
|
printf "\nKilling all running salt jobs.\n\n"
|
||||||
|
salt-call saltutil.kill_all_jobs
|
||||||
|
}
|
||||||
|
|
||||||
|
function soUserSync() {
|
||||||
|
# apply this state to update /opt/so/saltstack/local/salt/elasticsearch/curl.config on the manager
|
||||||
|
salt-call state.sls_id elastic_curl_config_distributed manager queue=True
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' saltutil.kill_all_jobs
|
||||||
|
# apply this state to get the curl.config
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' state.sls_id elastic_curl_config common queue=True
|
||||||
|
$(dirname $0)/so-user sync
|
||||||
|
printf "\nApplying logstash state to the appropriate nodes.\n\n"
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' state.apply logstash queue=True
|
||||||
|
printf "\nApplying filebeat state to the appropriate nodes.\n\n"
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode or G@role:so-sensor or G@role:so-fleet' state.apply filebeat queue=True
|
||||||
|
printf "\nApplying kibana state to the appropriate nodes.\n\n"
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch' state.apply kibana queue=True
|
||||||
|
printf "\nApplying curator state to the appropriate nodes.\n\n"
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' state.apply curator queue=True
|
||||||
|
}
|
||||||
|
|
||||||
|
function highstateManager() {
|
||||||
|
killAllSaltJobs
|
||||||
|
printf "\nRunning highstate on the manager to finalize password reset.\n\n"
|
||||||
|
salt-call state.highstate -linfo queue=True
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${user}" in
|
||||||
|
|
||||||
|
so_elastic | so_kibana | so_logstash | so_beats | so_monitor)
|
||||||
|
lock
|
||||||
|
killAllSaltJobs
|
||||||
|
disableSaltStates
|
||||||
|
removeSingleUserPass "$user"
|
||||||
|
createElasticAuthPillar
|
||||||
|
removeElasticUsersFile
|
||||||
|
unlock
|
||||||
|
soUserSync
|
||||||
|
enableSaltStates
|
||||||
|
highstateManager
|
||||||
|
;;
|
||||||
|
|
||||||
|
all)
|
||||||
|
lock
|
||||||
|
killAllSaltJobs
|
||||||
|
disableSaltStates
|
||||||
|
removeAllUserPass
|
||||||
|
createElasticAuthPillar
|
||||||
|
removeElasticUsersFile
|
||||||
|
unlock
|
||||||
|
soUserSync
|
||||||
|
enableSaltStates
|
||||||
|
highstateManager
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
fail "Unsupported user: $user"
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -50,7 +50,7 @@ done
|
|||||||
if [ $SKIP -ne 1 ]; then
|
if [ $SKIP -ne 1 ]; then
|
||||||
# List indices
|
# List indices
|
||||||
echo
|
echo
|
||||||
curl -k -L https://{{ NODEIP }}:9200/_cat/indices?v
|
{{ ELASTICCURL }} -k -L https://{{ NODEIP }}:9200/_cat/indices?v
|
||||||
echo
|
echo
|
||||||
# Inform user we are about to delete all data
|
# Inform user we are about to delete all data
|
||||||
echo
|
echo
|
||||||
@@ -89,10 +89,10 @@ fi
|
|||||||
# Delete data
|
# Delete data
|
||||||
echo "Deleting data..."
|
echo "Deleting data..."
|
||||||
|
|
||||||
INDXS=$(curl -s -XGET -k -L https://{{ NODEIP }}:9200/_cat/indices?v | egrep 'logstash|elastalert|so-' | awk '{ print $3 }')
|
INDXS=$({{ ELASTICCURL }} -s -XGET -k -L https://{{ NODEIP }}:9200/_cat/indices?v | egrep 'logstash|elastalert|so-' | awk '{ print $3 }')
|
||||||
for INDX in ${INDXS}
|
for INDX in ${INDXS}
|
||||||
do
|
do
|
||||||
curl -XDELETE -k -L https://"{{ NODEIP }}:9200/${INDX}" > /dev/null 2>&1
|
{{ ELASTICCURL }} -XDELETE -k -L https://"{{ NODEIP }}:9200/${INDX}" > /dev/null 2>&1
|
||||||
done
|
done
|
||||||
|
|
||||||
#Start Logstash/Filebeat
|
#Start Logstash/Filebeat
|
||||||
|
|||||||
@@ -18,4 +18,4 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_cat/indices?pretty
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_cat/indices?pretty
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ THEHIVEESPORT=9400
|
|||||||
|
|
||||||
echo "Removing read only attributes for indices..."
|
echo "Removing read only attributes for indices..."
|
||||||
echo
|
echo
|
||||||
curl -s -k -XPUT -H "Content-Type: application/json" -L https://$IP:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}' 2>&1 | if grep -q ack; then echo "Index settings updated..."; else echo "There was any issue updating the read-only attribute. Please ensure Elasticsearch is running.";fi;
|
{{ ELASTICCURL }} -s -k -XPUT -H "Content-Type: application/json" -L https://$IP:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}' 2>&1 | if grep -q ack; then echo "Index settings updated..."; else echo "There was any issue updating the read-only attribute. Please ensure Elasticsearch is running.";fi;
|
||||||
curl -XPUT -H "Content-Type: application/json" -L http://$IP:9400/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}' 2>&1 | if grep -q ack; then echo "Index settings updated..."; else echo "There was any issue updating the read-only attribute. Please ensure Elasticsearch is running.";fi;
|
{{ ELASTICCURL }} -XPUT -H "Content-Type: application/json" -L http://$IP:9400/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}' 2>&1 | if grep -q ack; then echo "Index settings updated..."; else echo "There was any issue updating the read-only attribute. Please ensure Elasticsearch is running.";fi;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
if [ "$1" == "" ]; then
|
if [ "$1" == "" ]; then
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_nodes/stats | jq .nodes | jq ".[] | .ingest.pipelines"
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_nodes/stats | jq .nodes | jq ".[] | .ingest.pipelines"
|
||||||
else
|
else
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_nodes/stats | jq .nodes | jq ".[] | .ingest.pipelines.\"$1\""
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_nodes/stats | jq .nodes | jq ".[] | .ingest.pipelines.\"$1\""
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
if [ "$1" == "" ]; then
|
if [ "$1" == "" ]; then
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/* | jq .
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/* | jq .
|
||||||
else
|
else
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/$1 | jq .
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/$1 | jq .[]
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{%- set NODEIP = salt['pillar.get']('elasticsearch:mainip', '') -%}
|
{%- set NODEIP = salt['pillar.get']('elasticsearch:mainip', '') -%}
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
if [ "$1" == "" ]; then
|
if [ "$1" == "" ]; then
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/* | jq 'keys'
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/* | jq 'keys'
|
||||||
else
|
else
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/$1 | jq
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_ingest/pipeline/$1 | jq
|
||||||
fi
|
fi
|
||||||
|
|||||||
37
salt/common/tools/sbin/so-elasticsearch-query
Executable file
37
salt/common/tools/sbin/so-elasticsearch-query
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Submit a cURL request to the local Security Onion Elasticsearch host."
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 <PATH> [ARGS,...]"
|
||||||
|
echo ""
|
||||||
|
echo "Where "
|
||||||
|
echo " PATH represents the elastic function being requested."
|
||||||
|
echo " ARGS is used to specify additional, optional curl parameters."
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 /"
|
||||||
|
echo " $0 '*:so-*/_search' -d '{\"query\": {\"match_all\": {}},\"size\": 1}' | jq"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
QUERYPATH=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
{{ ELASTICCURL }} -s -k -L -H "Content-Type: application/json" "https://localhost:9200/${QUERYPATH}" "$@"
|
||||||
57
salt/common/tools/sbin/so-elasticsearch-roles-load
Executable file
57
salt/common/tools/sbin/so-elasticsearch-roles-load
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
{%- set mainint = salt['pillar.get']('host:mainint') %}
|
||||||
|
{%- set MYIP = salt['grains.get']('ip_interfaces:' ~ mainint)[0] %}
|
||||||
|
|
||||||
|
default_conf_dir=/opt/so/conf
|
||||||
|
ELASTICSEARCH_HOST="{{ MYIP }}"
|
||||||
|
ELASTICSEARCH_PORT=9200
|
||||||
|
|
||||||
|
# Define a default directory to load roles from
|
||||||
|
ELASTICSEARCH_ROLES="$default_conf_dir/elasticsearch/roles/"
|
||||||
|
|
||||||
|
# Wait for ElasticSearch to initialize
|
||||||
|
echo -n "Waiting for ElasticSearch..."
|
||||||
|
COUNT=0
|
||||||
|
ELASTICSEARCH_CONNECTED="no"
|
||||||
|
while [[ "$COUNT" -le 240 ]]; do
|
||||||
|
{{ ELASTICCURL }} -k --output /dev/null --silent --head --fail -L https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT"
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
ELASTICSEARCH_CONNECTED="yes"
|
||||||
|
echo "connected!"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
((COUNT+=1))
|
||||||
|
sleep 1
|
||||||
|
echo -n "."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$ELASTICSEARCH_CONNECTED" == "no" ]; then
|
||||||
|
echo
|
||||||
|
echo -e "Connection attempt timed out. Unable to connect to ElasticSearch. \nPlease try: \n -checking log(s) in /var/log/elasticsearch/\n -running 'sudo docker ps' \n -running 'sudo so-elastic-restart'"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ${ELASTICSEARCH_ROLES}
|
||||||
|
|
||||||
|
echo "Loading templates..."
|
||||||
|
for role in *; do
|
||||||
|
name=$(echo "$role" | cut -d. -f1)
|
||||||
|
so-elasticsearch-query _security/role/$name -XPUT -d @"$role"
|
||||||
|
done
|
||||||
|
|
||||||
|
cd - >/dev/null
|
||||||
@@ -18,4 +18,4 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_cat/shards?pretty
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_cat/shards?pretty
|
||||||
|
|||||||
@@ -18,4 +18,4 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
curl -s -k -L -XDELETE https://{{ NODEIP }}:9200/_template/$1
|
{{ ELASTICCURL }} -s -k -L -XDELETE https://{{ NODEIP }}:9200/_template/$1
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
if [ "$1" == "" ]; then
|
if [ "$1" == "" ]; then
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_template/* | jq .
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_template/* | jq .
|
||||||
else
|
else
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_template/$1 | jq .
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_template/$1 | jq .
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{%- set NODEIP = salt['pillar.get']('elasticsearch:mainip', '') -%}
|
{%- set NODEIP = salt['pillar.get']('elasticsearch:mainip', '') -%}
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
if [ "$1" == "" ]; then
|
if [ "$1" == "" ]; then
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_template/* | jq 'keys'
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_template/* | jq 'keys'
|
||||||
else
|
else
|
||||||
curl -s -k -L https://{{ NODEIP }}:9200/_template/$1 | jq
|
{{ ELASTICCURL }} -s -k -L https://{{ NODEIP }}:9200/_template/$1 | jq
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{%- set mainint = salt['pillar.get']('host:mainint') %}
|
|
||||||
{%- set MYIP = salt['grains.get']('ip_interfaces:' ~ mainint)[0] %}
|
|
||||||
|
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,6 +14,9 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
{%- set mainint = salt['pillar.get']('host:mainint') %}
|
||||||
|
{%- set MYIP = salt['grains.get']('ip_interfaces:' ~ mainint)[0] %}
|
||||||
|
|
||||||
default_conf_dir=/opt/so/conf
|
default_conf_dir=/opt/so/conf
|
||||||
ELASTICSEARCH_HOST="{{ MYIP }}"
|
ELASTICSEARCH_HOST="{{ MYIP }}"
|
||||||
ELASTICSEARCH_PORT=9200
|
ELASTICSEARCH_PORT=9200
|
||||||
@@ -30,7 +30,7 @@ echo -n "Waiting for ElasticSearch..."
|
|||||||
COUNT=0
|
COUNT=0
|
||||||
ELASTICSEARCH_CONNECTED="no"
|
ELASTICSEARCH_CONNECTED="no"
|
||||||
while [[ "$COUNT" -le 240 ]]; do
|
while [[ "$COUNT" -le 240 ]]; do
|
||||||
curl -k --output /dev/null --silent --head --fail -L https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT"
|
{{ ELASTICCURL }} -k --output /dev/null --silent --head --fail -L https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT"
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
ELASTICSEARCH_CONNECTED="yes"
|
ELASTICSEARCH_CONNECTED="yes"
|
||||||
echo "connected!"
|
echo "connected!"
|
||||||
@@ -51,7 +51,7 @@ cd ${ELASTICSEARCH_TEMPLATES}
|
|||||||
|
|
||||||
|
|
||||||
echo "Loading templates..."
|
echo "Loading templates..."
|
||||||
for i in *; do TEMPLATE=$(echo $i | cut -d '-' -f2); echo "so-$TEMPLATE"; curl -k ${ELASTICSEARCH_AUTH} -s -XPUT -L https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}/_template/so-$TEMPLATE -H 'Content-Type: application/json' -d@$i 2>/dev/null; echo; done
|
for i in *; do TEMPLATE=$(echo $i | cut -d '-' -f2); echo "so-$TEMPLATE"; {{ ELASTICCURL }} -k ${ELASTICSEARCH_AUTH} -s -XPUT -L https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}/_template/so-$TEMPLATE -H 'Content-Type: application/json' -d@$i 2>/dev/null; echo; done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
cd - >/dev/null
|
cd - >/dev/null
|
||||||
|
|||||||
5
salt/common/tools/sbin/so-elasticsearch-wait
Executable file
5
salt/common/tools/sbin/so-elasticsearch-wait
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
wait_for_web_response "https://localhost:9200/_cat/indices/.kibana*" "green open" 300 "{{ ELASTICCURL }}"
|
||||||
67
salt/common/tools/sbin/so-filebeat-module-setup
Executable file
67
salt/common/tools/sbin/so-filebeat-module-setup
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
{%- set mainint = salt['pillar.get']('host:mainint') %}
|
||||||
|
{%- set MYIP = salt['grains.get']('ip_interfaces:' ~ mainint)[0] %}
|
||||||
|
|
||||||
|
default_conf_dir=/opt/so/conf
|
||||||
|
ELASTICSEARCH_HOST="{{ MYIP }}"
|
||||||
|
ELASTICSEARCH_PORT=9200
|
||||||
|
#ELASTICSEARCH_AUTH=""
|
||||||
|
|
||||||
|
# Define a default directory to load pipelines from
|
||||||
|
FB_MODULE_YML="/usr/share/filebeat/module-setup.yml"
|
||||||
|
|
||||||
|
|
||||||
|
# Wait for ElasticSearch to initialize
|
||||||
|
echo -n "Waiting for ElasticSearch..."
|
||||||
|
COUNT=0
|
||||||
|
ELASTICSEARCH_CONNECTED="no"
|
||||||
|
while [[ "$COUNT" -le 240 ]]; do
|
||||||
|
{{ ELASTICCURL }} -k --output /dev/null --silent --head --fail -L https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT"
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
ELASTICSEARCH_CONNECTED="yes"
|
||||||
|
echo "connected!"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
((COUNT+=1))
|
||||||
|
sleep 1
|
||||||
|
echo -n "."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$ELASTICSEARCH_CONNECTED" == "no" ]; then
|
||||||
|
echo
|
||||||
|
echo -e "Connection attempt timed out. Unable to connect to ElasticSearch. \nPlease try: \n -checking log(s) in /var/log/elasticsearch/\n -running 'sudo docker ps' \n -running 'sudo so-elastic-restart'"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
echo "Testing to see if the pipelines are already applied"
|
||||||
|
ESVER=$({{ ELASTICCURL }} -sk https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT" |jq .version.number |tr -d \")
|
||||||
|
PIPELINES=$({{ ELASTICCURL }} -sk https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_PORT"/_ingest/pipeline/filebeat-$ESVER-suricata-eve-pipeline | jq . | wc -c)
|
||||||
|
|
||||||
|
if [[ "$PIPELINES" -lt 5 ]]; then
|
||||||
|
echo "Setting up ingest pipeline(s)"
|
||||||
|
|
||||||
|
for MODULE in activemq apache auditd aws azure barracuda bluecoat cef checkpoint cisco coredns crowdstrike cyberark cylance elasticsearch envoyproxy f5 fortinet gcp google_workspace googlecloud gsuite haproxy ibmmq icinga iis imperva infoblox iptables juniper kafka kibana logstash microsoft mongodb mssql mysql nats netscout nginx o365 okta osquery panw postgresql rabbitmq radware redis santa snort snyk sonicwall sophos squid suricata system threatintel tomcat traefik zeek zscaler
|
||||||
|
do
|
||||||
|
echo "Loading $MODULE"
|
||||||
|
docker exec -i so-filebeat filebeat setup modules -pipelines -modules $MODULE -c $FB_MODULE_YML
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ def showUsage(options, args):
|
|||||||
print('')
|
print('')
|
||||||
print(' General commands:')
|
print(' General commands:')
|
||||||
print(' help - Prints this usage information.')
|
print(' help - Prints this usage information.')
|
||||||
|
print(' apply - Apply the firewall state.')
|
||||||
print('')
|
print('')
|
||||||
print(' Host commands:')
|
print(' Host commands:')
|
||||||
print(' listhostgroups - Lists the known host groups.')
|
print(' listhostgroups - Lists the known host groups.')
|
||||||
@@ -66,11 +67,11 @@ def checkDefaultPortsOption(options):
|
|||||||
|
|
||||||
def checkApplyOption(options):
|
def checkApplyOption(options):
|
||||||
if "--apply" in options:
|
if "--apply" in options:
|
||||||
return apply()
|
return apply(None, None)
|
||||||
|
|
||||||
def loadYaml(filename):
|
def loadYaml(filename):
|
||||||
file = open(filename, "r")
|
file = open(filename, "r")
|
||||||
return yaml.load(file.read())
|
return yaml.safe_load(file.read())
|
||||||
|
|
||||||
def writeYaml(filename, content):
|
def writeYaml(filename, content):
|
||||||
file = open(filename, "w")
|
file = open(filename, "w")
|
||||||
@@ -328,7 +329,7 @@ def removehost(options, args):
|
|||||||
code = checkApplyOption(options)
|
code = checkApplyOption(options)
|
||||||
return code
|
return code
|
||||||
|
|
||||||
def apply():
|
def apply(options, args):
|
||||||
proc = subprocess.run(['salt-call', 'state.apply', 'firewall', 'queue=True'])
|
proc = subprocess.run(['salt-call', 'state.apply', 'firewall', 'queue=True'])
|
||||||
return proc.returncode
|
return proc.returncode
|
||||||
|
|
||||||
@@ -356,7 +357,8 @@ def main():
|
|||||||
"addport": addport,
|
"addport": addport,
|
||||||
"removeport": removeport,
|
"removeport": removeport,
|
||||||
"addhostgroup": addhostgroup,
|
"addhostgroup": addhostgroup,
|
||||||
"addportgroup": addportgroup
|
"addportgroup": addportgroup,
|
||||||
|
"apply": apply
|
||||||
}
|
}
|
||||||
|
|
||||||
code=1
|
code=1
|
||||||
|
|||||||
@@ -2,11 +2,16 @@
|
|||||||
|
|
||||||
#so-fleet-setup $FleetEmail $FleetPassword
|
#so-fleet-setup $FleetEmail $FleetPassword
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
if [[ $# -ne 2 ]] ; then
|
if [[ $# -ne 2 ]] ; then
|
||||||
echo "Username or Password was not set - exiting now."
|
echo "Username or Password was not set - exiting now."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
USER_EMAIL=$1
|
||||||
|
USER_PW=$2
|
||||||
|
|
||||||
# Checking to see if required containers are started...
|
# Checking to see if required containers are started...
|
||||||
if [ ! "$(docker ps -q -f name=so-fleet)" ]; then
|
if [ ! "$(docker ps -q -f name=so-fleet)" ]; then
|
||||||
echo "Starting Docker Containers..."
|
echo "Starting Docker Containers..."
|
||||||
@@ -17,8 +22,16 @@ fi
|
|||||||
|
|
||||||
docker exec so-fleet fleetctl config set --address https://127.0.0.1:8080 --tls-skip-verify --url-prefix /fleet
|
docker exec so-fleet fleetctl config set --address https://127.0.0.1:8080 --tls-skip-verify --url-prefix /fleet
|
||||||
docker exec so-fleet bash -c 'while [[ "$(curl -s -o /dev/null --insecure -w ''%{http_code}'' https://127.0.0.1:8080/fleet)" != "301" ]]; do sleep 5; done'
|
docker exec so-fleet bash -c 'while [[ "$(curl -s -o /dev/null --insecure -w ''%{http_code}'' https://127.0.0.1:8080/fleet)" != "301" ]]; do sleep 5; done'
|
||||||
docker exec so-fleet fleetctl setup --email $1 --password $2
|
|
||||||
|
|
||||||
|
# Create Security Onion Fleet Service Account + Setup Fleet
|
||||||
|
FLEET_SA_EMAIL=$(lookup_pillar_secret fleet_sa_email)
|
||||||
|
FLEET_SA_PW=$(lookup_pillar_secret fleet_sa_password)
|
||||||
|
docker exec so-fleet fleetctl setup --email $FLEET_SA_EMAIL --password $FLEET_SA_PW --name SO_ServiceAccount --org-name SO
|
||||||
|
|
||||||
|
# Create User Account
|
||||||
|
echo "$USER_PW" | so-fleet-user-add "$USER_EMAIL"
|
||||||
|
|
||||||
|
# Import Packs & Configs
|
||||||
docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml
|
docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml
|
||||||
docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/Windows/osquery.yaml
|
docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/Windows/osquery.yaml
|
||||||
docker exec so-fleet fleetctl apply -f /packs/so/so-default.yml
|
docker exec so-fleet fleetctl apply -f /packs/so/so-default.yml
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "Usage: $0 <new-user-name>"
|
echo "Usage: $0 <new-user-email>"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Adds a new user to Fleet. The new password will be read from STDIN."
|
echo "Adds a new user to Fleet. The new password will be read from STDIN."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -28,37 +28,42 @@ if [ $# -ne 1 ]; then
|
|||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
USER=$1
|
|
||||||
|
|
||||||
MYSQL_PASS=$(lookup_pillar_secret mysql)
|
USER_EMAIL=$1
|
||||||
FLEET_IP=$(lookup_pillar fleet_ip)
|
FLEET_SA_EMAIL=$(lookup_pillar_secret fleet_sa_email)
|
||||||
FLEET_USER=$USER
|
FLEET_SA_PW=$(lookup_pillar_secret fleet_sa_password)
|
||||||
|
MYSQL_PW=$(lookup_pillar_secret mysql)
|
||||||
|
|
||||||
# Read password for new user from stdin
|
# Read password for new user from stdin
|
||||||
test -t 0
|
test -t 0
|
||||||
if [[ $? == 0 ]]; then
|
if [[ $? == 0 ]]; then
|
||||||
echo "Enter new password:"
|
echo "Enter new password:"
|
||||||
fi
|
fi
|
||||||
read -rs FLEET_PASS
|
read -rs USER_PASS
|
||||||
|
|
||||||
if ! check_password "$FLEET_PASS"; then
|
check_password_and_exit "$USER_PASS"
|
||||||
echo "Password is invalid. Please exclude single quotes, double quotes and backslashes from the password."
|
|
||||||
exit 2
|
# Config fleetctl & login with the SO Service Account
|
||||||
fi
|
CONFIG_OUTPUT=$(docker exec so-fleet fleetctl config set --address https://127.0.0.1:8080 --tls-skip-verify --url-prefix /fleet 2>&1 )
|
||||||
|
SALOGIN_OUTPUT=$(docker exec so-fleet fleetctl login --email $FLEET_SA_EMAIL --password $FLEET_SA_PW 2>&1)
|
||||||
|
|
||||||
FLEET_HASH=$(docker exec so-soctopus python -c "import bcrypt; print(bcrypt.hashpw('$FLEET_PASS'.encode('utf-8'), bcrypt.gensalt()).decode('utf-8'));" 2>&1)
|
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo "Failed to generate Fleet password hash"
|
echo "Unable to add user to Fleet; Fleet Service account login failed"
|
||||||
|
echo "$SALOGIN_OUTPUT"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PASS fleet -e \
|
# Create New User
|
||||||
"INSERT INTO users (password,salt,username,email,admin,enabled) VALUES ('$FLEET_HASH','','$FLEET_USER','$FLEET_USER',1,1)" 2>&1)
|
CREATE_OUTPUT=$(docker exec so-fleet fleetctl user create --email $USER_EMAIL --name $USER_EMAIL --password $USER_PASS --global-role admin 2>&1)
|
||||||
|
|
||||||
if [[ $? -eq 0 ]]; then
|
if [[ $? -eq 0 ]]; then
|
||||||
echo "Successfully added user to Fleet"
|
echo "Successfully added user to Fleet"
|
||||||
else
|
else
|
||||||
echo "Unable to add user to Fleet; user might already exist"
|
echo "Unable to add user to Fleet; user might already exist"
|
||||||
echo "$MYSQL_OUTPUT"
|
echo "$CREATE_OUTPUT"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Disable forced password reset
|
||||||
|
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PW fleet -e \
|
||||||
|
"UPDATE users SET admin_forced_password_reset = 0 WHERE email = '$USER_EMAIL'" 2>&1)
|
||||||
56
salt/common/tools/sbin/so-fleet-user-delete
Normal file
56
salt/common/tools/sbin/so-fleet-user-delete
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <user-email>"
|
||||||
|
echo ""
|
||||||
|
echo "Deletes a user in Fleet"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
USER_EMAIL=$1
|
||||||
|
FLEET_SA_EMAIL=$(lookup_pillar_secret fleet_sa_email)
|
||||||
|
FLEET_SA_PW=$(lookup_pillar_secret fleet_sa_password)
|
||||||
|
|
||||||
|
# Config fleetctl & login with the SO Service Account
|
||||||
|
CONFIG_OUTPUT=$(docker exec so-fleet fleetctl config set --address https://127.0.0.1:8080 --tls-skip-verify --url-prefix /fleet 2>&1 )
|
||||||
|
SALOGIN_OUTPUT=$(docker exec so-fleet fleetctl login --email $FLEET_SA_EMAIL --password $FLEET_SA_PW 2>&1)
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "Unable to delete user from Fleet; Fleet Service account login failed"
|
||||||
|
echo "$SALOGIN_OUTPUT"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Delete User
|
||||||
|
DELETE_OUTPUT=$(docker exec so-fleet fleetctl user delete --email $USER_EMAIL 2>&1)
|
||||||
|
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo "Successfully deleted user from Fleet"
|
||||||
|
else
|
||||||
|
echo "Unable to delete user from Fleet"
|
||||||
|
echo "$DELETE_OUTPUT"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
75
salt/common/tools/sbin/so-fleet-user-update
Executable file
75
salt/common/tools/sbin/so-fleet-user-update
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <user-name>"
|
||||||
|
echo ""
|
||||||
|
echo "Update password for an existing Fleet user. The new password will be read from STDIN."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
USER=$1
|
||||||
|
|
||||||
|
MYSQL_PASS=$(lookup_pillar_secret mysql)
|
||||||
|
FLEET_IP=$(lookup_pillar fleet_ip)
|
||||||
|
FLEET_USER=$USER
|
||||||
|
|
||||||
|
# test existence of user
|
||||||
|
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PASS fleet -e \
|
||||||
|
"SELECT count(1) FROM users WHERE email='$FLEET_USER'" 2>/dev/null | tail -1)
|
||||||
|
if [[ $? -ne 0 ]] || [[ $MYSQL_OUTPUT -ne 1 ]] ; then
|
||||||
|
echo "Test for email [${FLEET_USER}] failed"
|
||||||
|
echo " expect 1 hit in users database, return $MYSQL_OUTPUT hit(s)."
|
||||||
|
echo "Unable to update Fleet user password."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Read password for new user from stdin
|
||||||
|
test -t 0
|
||||||
|
if [[ $? == 0 ]]; then
|
||||||
|
echo "Enter new password:"
|
||||||
|
fi
|
||||||
|
read -rs FLEET_PASS
|
||||||
|
|
||||||
|
if ! check_password "$FLEET_PASS"; then
|
||||||
|
echo "Password is invalid. Please exclude single quotes, double quotes, dollar signs, and backslashes from the password."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
FLEET_HASH=$(docker exec so-soctopus python -c "import bcrypt; print(bcrypt.hashpw('$FLEET_PASS'.encode('utf-8'), bcrypt.gensalt()).decode('utf-8'));" 2>&1)
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "Failed to generate Fleet password hash"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PASS fleet -e \
|
||||||
|
"UPDATE users SET password='$FLEET_HASH', salt='' where email='$FLEET_USER'" 2>&1)
|
||||||
|
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo "Successfully updated Fleet user password"
|
||||||
|
else
|
||||||
|
echo "Unable to update Fleet user password"
|
||||||
|
echo "$MYSQL_OUTPUT"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
17
salt/common/tools/sbin/so-grafana-dashboard-folder-delete
Executable file
17
salt/common/tools/sbin/so-grafana-dashboard-folder-delete
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
# this script is used to delete the default Grafana dashboard folders that existed prior to Grafana dashboard and Salt management changes in 2.3.70
|
||||||
|
|
||||||
|
folders=$(curl -X GET http://admin:{{salt['pillar.get']('secrets:grafana_admin')}}@localhost:3000/api/folders | jq -r '.[] | @base64')
|
||||||
|
delfolder=("Manager" "Manager Search" "Sensor Nodes" "Search Nodes" "Standalone" "Eval Mode")
|
||||||
|
|
||||||
|
for row in $folders; do
|
||||||
|
title=$(echo ${row} | base64 --decode | jq -r '.title')
|
||||||
|
uid=$(echo ${row} | base64 --decode | jq -r '.uid')
|
||||||
|
|
||||||
|
if [[ " ${delfolder[@]} " =~ " ${title} " ]]; then
|
||||||
|
curl -X DELETE http://admin:{{salt['pillar.get']('secrets:grafana_admin')}}@localhost:3000/api/folders/$uid
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "so-grafana-dashboard-folder-delete has been run to delete default Grafana dashboard folders that existed prior to 2.3.70" > /opt/so/state/so-grafana-dashboard-folder-delete-complete
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -17,7 +17,9 @@
|
|||||||
|
|
||||||
# NOTE: This script depends on so-common
|
# NOTE: This script depends on so-common
|
||||||
IMAGEREPO=security-onion-solutions
|
IMAGEREPO=security-onion-solutions
|
||||||
|
STATUS_CONF='/opt/so/conf/so-status/so-status.conf'
|
||||||
|
|
||||||
|
# shellcheck disable=SC2120
|
||||||
container_list() {
|
container_list() {
|
||||||
MANAGERCHECK=$1
|
MANAGERCHECK=$1
|
||||||
|
|
||||||
@@ -128,13 +130,18 @@ update_docker_containers() {
|
|||||||
mkdir -p $SIGNPATH >> "$LOG_FILE" 2>&1
|
mkdir -p $SIGNPATH >> "$LOG_FILE" 2>&1
|
||||||
|
|
||||||
# Let's make sure we have the public key
|
# Let's make sure we have the public key
|
||||||
retry 50 10 "curl -sSL https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS -o $SIGNPATH/KEYS" >> "$LOG_FILE" 2>&1
|
run_check_net_err \
|
||||||
|
"curl --retry 5 --retry-delay 60 -sSL https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS -o $SIGNPATH/KEYS" \
|
||||||
|
"Could not pull signature key file, please ensure connectivity to https://raw.gihubusercontent.com" \
|
||||||
|
noretry >> "$LOG_FILE" 2>&1
|
||||||
result=$?
|
result=$?
|
||||||
if [[ $result -eq 0 ]]; then
|
if [[ $result -eq 0 ]]; then
|
||||||
cat $SIGNPATH/KEYS | gpg --import - >> "$LOG_FILE" 2>&1
|
cat $SIGNPATH/KEYS | gpg --import - >> "$LOG_FILE" 2>&1
|
||||||
else
|
fi
|
||||||
echo "Failed to pull signature key file: $result"
|
|
||||||
exit 1
|
# If downloading for soup, check if any optional images need to be pulled
|
||||||
|
if [[ $CURLTYPE == 'soup' ]]; then
|
||||||
|
grep -q "so-logscan" "$STATUS_CONF" && TRUSTED_CONTAINERS+=("so-logscan")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Download the containers from the interwebs
|
# Download the containers from the interwebs
|
||||||
@@ -148,14 +155,15 @@ update_docker_containers() {
|
|||||||
|
|
||||||
# Pull down the trusted docker image
|
# Pull down the trusted docker image
|
||||||
local image=$i:$VERSION$IMAGE_TAG_SUFFIX
|
local image=$i:$VERSION$IMAGE_TAG_SUFFIX
|
||||||
retry 50 10 "docker pull $CONTAINER_REGISTRY/$IMAGEREPO/$image" >> "$LOG_FILE" 2>&1
|
run_check_net_err \
|
||||||
|
"docker pull $CONTAINER_REGISTRY/$IMAGEREPO/$image" \
|
||||||
|
"Could not pull $image, please ensure connectivity to $CONTAINER_REGISTRY" >> "$LOG_FILE" 2>&1
|
||||||
|
|
||||||
# Get signature
|
# Get signature
|
||||||
retry 50 10 "curl -A '$CURLTYPE/$CURRENTVERSION/$OS/$(uname -r)' https://sigs.securityonion.net/$VERSION/$i:$VERSION$IMAGE_TAG_SUFFIX.sig --output $SIGNPATH/$image.sig" >> "$LOG_FILE" 2>&1
|
run_check_net_err \
|
||||||
if [[ $? -ne 0 ]]; then
|
"curl --retry 5 --retry-delay 60 -A '$CURLTYPE/$CURRENTVERSION/$OS/$(uname -r)' https://sigs.securityonion.net/$VERSION/$i:$VERSION$IMAGE_TAG_SUFFIX.sig --output $SIGNPATH/$image.sig" \
|
||||||
echo "Unable to pull signature file for $image" >> "$LOG_FILE" 2>&1
|
"Could not pull signature file for $image, please ensure connectivity to https://sigs.securityonion.net " \
|
||||||
exit 1
|
noretry >> "$LOG_FILE" 2>&1
|
||||||
fi
|
|
||||||
# Dump our hash values
|
# Dump our hash values
|
||||||
DOCKERINSPECT=$(docker inspect $CONTAINER_REGISTRY/$IMAGEREPO/$image)
|
DOCKERINSPECT=$(docker inspect $CONTAINER_REGISTRY/$IMAGEREPO/$image)
|
||||||
|
|
||||||
|
|||||||
58
salt/common/tools/sbin/so-image-pull
Executable file
58
salt/common/tools/sbin/so-image-pull
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
. /usr/sbin/so-image-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
read -r -d '' message <<- EOM
|
||||||
|
usage: so-image-pull [-h] IMAGE [IMAGE ...]
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
IMAGE One or more 'so-' prefixed images to download and verify.
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help Show this help message and exit.
|
||||||
|
EOM
|
||||||
|
echo "$message"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg; do
|
||||||
|
shift
|
||||||
|
[[ "$arg" = "--quiet" || "$arg" = "-q" ]] && quiet=true && continue
|
||||||
|
set -- "$@" "$arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $# -eq 0 || $# -gt 1 ]] || [[ $1 == '-h' || $1 == '--help' ]]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
TRUSTED_CONTAINERS=("$@")
|
||||||
|
set_version
|
||||||
|
|
||||||
|
for image in "${TRUSTED_CONTAINERS[@]}"; do
|
||||||
|
if ! docker images | grep "$image" | grep ":5000" | grep -q "$VERSION"; then
|
||||||
|
if [[ $quiet == true ]]; then
|
||||||
|
update_docker_containers "$image" "" "" "/dev/null"
|
||||||
|
else
|
||||||
|
update_docker_containers "$image" "" "" ""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$image:$VERSION image exists."
|
||||||
|
fi
|
||||||
|
done
|
||||||
176
salt/common/tools/sbin/so-import-evtx
Executable file
176
salt/common/tools/sbin/so-import-evtx
Executable file
@@ -0,0 +1,176 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
{%- set MANAGER = salt['grains.get']('master') %}
|
||||||
|
{%- set VERSION = salt['pillar.get']('global:soversion') %}
|
||||||
|
{%- set IMAGEREPO = salt['pillar.get']('global:imagerepo') %}
|
||||||
|
{%- set MANAGERIP = salt['pillar.get']('global:managerip') -%}
|
||||||
|
{%- set URLBASE = salt['pillar.get']('global:url_base') %}
|
||||||
|
{% set ES_USER = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:user', '') %}
|
||||||
|
{% set ES_PW = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') %}
|
||||||
|
|
||||||
|
INDEX_DATE=$(date +'%Y.%m.%d')
|
||||||
|
RUNID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)
|
||||||
|
LOG_FILE=/nsm/import/evtx-import.log
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
cat << EOF
|
||||||
|
Usage: $0 <evtx-file-1> [evtx-file-2] [evtx-file-*]
|
||||||
|
|
||||||
|
Imports one or more evtx files into Security Onion. The evtx files will be analyzed and made available for review in the Security Onion toolset.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function evtx2es() {
|
||||||
|
EVTX=$1
|
||||||
|
HASH=$2
|
||||||
|
|
||||||
|
ES_PW=$(lookup_pillar "auth:users:so_elastic_user:pass" "elasticsearch")
|
||||||
|
ES_USER=$(lookup_pillar "auth:users:so_elastic_user:user" "elasticsearch")
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "$EVTX:/tmp/$RUNID.evtx" \
|
||||||
|
--entrypoint evtx2es \
|
||||||
|
{{ MANAGER }}:5000/{{ IMAGEREPO }}/so-pcaptools:{{ VERSION }} \
|
||||||
|
--host {{ MANAGERIP }} --scheme https \
|
||||||
|
--index so-beats-$INDEX_DATE --pipeline import.wel \
|
||||||
|
--login $ES_USER --pwd $ES_PW \
|
||||||
|
"/tmp/$RUNID.evtx" >> $LOG_FILE 2>&1
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "$EVTX:/tmp/import.evtx" \
|
||||||
|
-v "/nsm/import/evtx-end_newest:/tmp/newest" \
|
||||||
|
-v "/nsm/import/evtx-start_oldest:/tmp/oldest" \
|
||||||
|
--entrypoint '/evtx_calc_timestamps.sh' \
|
||||||
|
{{ MANAGER }}:5000/{{ IMAGEREPO }}/so-pcaptools:{{ VERSION }}
|
||||||
|
}
|
||||||
|
|
||||||
|
# if no parameters supplied, display usage
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ensure this is a Manager node
|
||||||
|
require_manager
|
||||||
|
|
||||||
|
# verify that all parameters are files
|
||||||
|
for i in "$@"; do
|
||||||
|
if ! [ -f "$i" ]; then
|
||||||
|
usage
|
||||||
|
echo "\"$i\" is not a valid file!"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# track if we have any valid or invalid evtx
|
||||||
|
INVALID_EVTXS="no"
|
||||||
|
VALID_EVTXS="no"
|
||||||
|
|
||||||
|
# track oldest start and newest end so that we can generate the Kibana search hyperlink at the end
|
||||||
|
START_OLDEST="2050-12-31"
|
||||||
|
END_NEWEST="1971-01-01"
|
||||||
|
|
||||||
|
touch /nsm/import/evtx-start_oldest
|
||||||
|
touch /nsm/import/evtx-end_newest
|
||||||
|
|
||||||
|
echo $START_OLDEST > /nsm/import/evtx-start_oldest
|
||||||
|
echo $END_NEWEST > /nsm/import/evtx-end_newest
|
||||||
|
|
||||||
|
# paths must be quoted in case they include spaces
|
||||||
|
for EVTX in "$@"; do
|
||||||
|
EVTX=$(/usr/bin/realpath "$EVTX")
|
||||||
|
echo "Processing Import: ${EVTX}"
|
||||||
|
|
||||||
|
# generate a unique hash to assist with dedupe checks
|
||||||
|
HASH=$(md5sum "${EVTX}" | awk '{ print $1 }')
|
||||||
|
HASH_DIR=/nsm/import/${HASH}
|
||||||
|
echo "- assigning unique identifier to import: $HASH"
|
||||||
|
|
||||||
|
if [ -d $HASH_DIR ]; then
|
||||||
|
echo "- this EVTX has already been imported; skipping"
|
||||||
|
INVALID_EVTXS="yes"
|
||||||
|
else
|
||||||
|
VALID_EVTXS="yes"
|
||||||
|
|
||||||
|
EVTX_DIR=$HASH_DIR/evtx
|
||||||
|
mkdir -p $EVTX_DIR
|
||||||
|
|
||||||
|
# import evtx and write them to import ingest pipeline
|
||||||
|
echo "- importing logs to Elasticsearch..."
|
||||||
|
evtx2es "${EVTX}" $HASH
|
||||||
|
|
||||||
|
# compare $START to $START_OLDEST
|
||||||
|
START=$(cat /nsm/import/evtx-start_oldest)
|
||||||
|
START_COMPARE=$(date -d $START +%s)
|
||||||
|
START_OLDEST_COMPARE=$(date -d $START_OLDEST +%s)
|
||||||
|
if [ $START_COMPARE -lt $START_OLDEST_COMPARE ]; then
|
||||||
|
START_OLDEST=$START
|
||||||
|
fi
|
||||||
|
|
||||||
|
# compare $ENDNEXT to $END_NEWEST
|
||||||
|
END=$(cat /nsm/import/evtx-end_newest)
|
||||||
|
ENDNEXT=`date +%Y-%m-%d --date="$END 1 day"`
|
||||||
|
ENDNEXT_COMPARE=$(date -d $ENDNEXT +%s)
|
||||||
|
END_NEWEST_COMPARE=$(date -d $END_NEWEST +%s)
|
||||||
|
if [ $ENDNEXT_COMPARE -gt $END_NEWEST_COMPARE ]; then
|
||||||
|
END_NEWEST=$ENDNEXT
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -f "${EVTX}" "${EVTX_DIR}"/data.evtx
|
||||||
|
chmod 644 "${EVTX_DIR}"/data.evtx
|
||||||
|
|
||||||
|
fi # end of valid evtx
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
done # end of for-loop processing evtx files
|
||||||
|
|
||||||
|
# remove temp files
|
||||||
|
echo "Cleaning up:"
|
||||||
|
for TEMP_EVTX in ${TEMP_EVTXS[@]}; do
|
||||||
|
echo "- removing temporary evtx $TEMP_EVTX"
|
||||||
|
rm -f $TEMP_EVTX
|
||||||
|
done
|
||||||
|
|
||||||
|
# output final messages
|
||||||
|
if [ "$INVALID_EVTXS" = "yes" ]; then
|
||||||
|
echo
|
||||||
|
echo "Please note! One or more evtx was invalid! You can scroll up to see which ones were invalid."
|
||||||
|
fi
|
||||||
|
|
||||||
|
START_OLDEST_FORMATTED=`date +%Y-%m-%d --date="$START_OLDEST"`
|
||||||
|
START_OLDEST_SLASH=$(echo $START_OLDEST_FORMATTED | sed -e 's/-/%2F/g')
|
||||||
|
END_NEWEST_SLASH=$(echo $END_NEWEST | sed -e 's/-/%2F/g')
|
||||||
|
|
||||||
|
if [ "$VALID_EVTXS" = "yes" ]; then
|
||||||
|
cat << EOF
|
||||||
|
|
||||||
|
Import complete!
|
||||||
|
|
||||||
|
You can use the following hyperlink to view data in the time range of your import. You can triple-click to quickly highlight the entire hyperlink and you can then copy it into your browser:
|
||||||
|
https://{{ URLBASE }}/#/hunt?q=import.id:${RUNID}%20%7C%20groupby%20event.module%20event.dataset&t=${START_OLDEST_SLASH}%2000%3A00%3A00%20AM%20-%20${END_NEWEST_SLASH}%2000%3A00%3A00%20AM&z=UTC
|
||||||
|
|
||||||
|
or you can manually set your Time Range to be (in UTC):
|
||||||
|
From: $START_OLDEST_FORMATTED To: $END_NEWEST
|
||||||
|
|
||||||
|
Please note that it may take 30 seconds or more for events to appear in Hunt.
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
@@ -132,6 +132,8 @@ for PCAP in "$@"; do
|
|||||||
PCAP_FIXED=`mktemp /tmp/so-import-pcap-XXXXXXXXXX.pcap`
|
PCAP_FIXED=`mktemp /tmp/so-import-pcap-XXXXXXXXXX.pcap`
|
||||||
echo "- attempting to recover corrupted PCAP file"
|
echo "- attempting to recover corrupted PCAP file"
|
||||||
pcapfix "${PCAP}" "${PCAP_FIXED}"
|
pcapfix "${PCAP}" "${PCAP_FIXED}"
|
||||||
|
# Make fixed file world readable since the Suricata docker container will runas a non-root user
|
||||||
|
chmod a+r "${PCAP_FIXED}"
|
||||||
PCAP="${PCAP_FIXED}"
|
PCAP="${PCAP_FIXED}"
|
||||||
TEMP_PCAPS+=(${PCAP_FIXED})
|
TEMP_PCAPS+=(${PCAP_FIXED})
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
curl -X GET -k -L "https://localhost:9200/_cat/indices?v&s=index"
|
{{ ELASTICCURL }} -X GET -k -L "https://localhost:9200/_cat/indices?v&s=index"
|
||||||
|
|||||||
53
salt/common/tools/sbin/so-influxdb-clean
Executable file
53
salt/common/tools/sbin/so-influxdb-clean
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
wdurregex="^[0-9]+w$"
|
||||||
|
ddurregex="^[0-9]+d$"
|
||||||
|
|
||||||
|
echo -e "\nThis script is used to reduce the size of InfluxDB by removing old data and retaining only the duration specified."
|
||||||
|
echo "The duration will need to be specified as an integer followed by the duration unit without a space."
|
||||||
|
echo -e "\nFor example, to purge all data but retain the past 12 weeks, specify 12w for the duration."
|
||||||
|
echo "The duration units are as follows:"
|
||||||
|
echo " w - week(s)"
|
||||||
|
echo " d - day(s)"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
echo ""
|
||||||
|
read -p 'Enter the duration of past data that you would like to retain: ' duration
|
||||||
|
duration=$(echo $duration | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
if [[ "$duration" =~ $wdurregex ]] || [[ "$duration" =~ $ddurregex ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\nInvalid duration."
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "\nInfluxDB will now be cleaned and leave only the past $duration worth of data."
|
||||||
|
read -r -p "Are you sure you want to continue? [y/N] " yorn
|
||||||
|
if [[ "$yorn" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
||||||
|
echo -e "\nCleaning InfluxDb and saving only the past $duration. This may could take several minutes depending on how much data needs to be cleaned."
|
||||||
|
if docker exec -t so-influxdb /bin/bash -c "influx -ssl -unsafeSsl -database telegraf -execute \"DELETE FROM /.*/ WHERE \"time\" >= '2020-01-01T00:00:00.0000000Z' AND \"time\" <= now() - $duration\""; then
|
||||||
|
echo -e "\nInfluxDb clean complete."
|
||||||
|
else
|
||||||
|
echo -e "\nSomething went wrong with cleaning InfluxDB. Please verify that the so-influxdb Docker container is running, and check the log at /opt/so/log/influxdb/influxdb.log for any details."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\nExiting as requested."
|
||||||
|
fi
|
||||||
63
salt/common/tools/sbin/so-influxdb-downsample
Executable file
63
salt/common/tools/sbin/so-influxdb-downsample
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
{%- set role = grains.id.split('_') | last %}
|
||||||
|
{%- if role in ['manager', 'managersearch', 'eval', 'standalone'] %}
|
||||||
|
{%- import_yaml 'influxdb/defaults.yaml' as default_settings %}
|
||||||
|
{%- set influxdb = salt['grains.filter_by'](default_settings, default='influxdb', merge=salt['pillar.get']('influxdb', {})) %}
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
echo -e "\nThis script is used to reduce the size of InfluxDB by downsampling old data into the so_long_term retention policy."
|
||||||
|
|
||||||
|
echo -e "\nInfluxDB will now be downsampled. This could take a few hours depending on how large the database is and hardware resources available."
|
||||||
|
read -r -p "Are you sure you want to continue? [y/N] " yorn
|
||||||
|
if [[ "$yorn" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
||||||
|
echo -e "\nDownsampling InfluxDb started at `date`. This may take several hours depending on how much data needs to be downsampled."
|
||||||
|
|
||||||
|
{% for dest_rp in influxdb.downsample.keys() -%}
|
||||||
|
{% for measurement in influxdb.downsample[dest_rp].get('measurements', []) -%}
|
||||||
|
|
||||||
|
day=0
|
||||||
|
startdate=`date`
|
||||||
|
while docker exec -t so-influxdb /bin/bash -c "influx -ssl -unsafeSsl -database telegraf -execute \"SELECT mean(*) INTO \"so_long_term\".\"{{measurement}}\" FROM \"autogen\".\"{{measurement}}\" WHERE \"time\" >= '2020-07-21T00:00:00.0000000Z' + ${day}d AND \"time\" <= '2020-07-21T00:00:00.0000000Z' + $((day+1))d GROUP BY time(5m),*\""; do
|
||||||
|
# why 2020-07-21?
|
||||||
|
migrationdate=`date -d "2020-07-21 + ${day} days" +"%y-%m-%d"`
|
||||||
|
|
||||||
|
echo "Downsampling of measurement: {{measurement}} from $migrationdate started at $startdate and completed at `date`."
|
||||||
|
|
||||||
|
newdaytomigrate=$(date -d "$migrationdate + 1 days" +"%s")
|
||||||
|
today=$(date +"%s")
|
||||||
|
if [ $newdaytomigrate -ge $today ]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
((day=day+1))
|
||||||
|
startdate=`date`
|
||||||
|
echo -e "\nDownsampling the next day's worth of data for measurement: {{measurement}}."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
{% endfor -%}
|
||||||
|
{% endfor -%}
|
||||||
|
|
||||||
|
echo -e "\nInfluxDb data downsampling complete."
|
||||||
|
|
||||||
|
else
|
||||||
|
echo -e "\nExiting as requested."
|
||||||
|
fi
|
||||||
|
{%- else %}
|
||||||
|
echo -e "\nThis script can only be run on a node running InfluxDB."
|
||||||
|
{%- endif %}
|
||||||
34
salt/common/tools/sbin/so-influxdb-drop-autogen
Executable file
34
salt/common/tools/sbin/so-influxdb-drop-autogen
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
echo -e "\nThis script is used to reduce the size of InfluxDB by dropping the autogen retention policy."
|
||||||
|
echo "If you want to retain historical data prior to 2.3.60, then this should only be run after you have downsampled your data using so-influxdb-downsample."
|
||||||
|
|
||||||
|
echo -e "\nThe autogen retention policy will now be dropped from InfluxDB."
|
||||||
|
read -r -p "Are you sure you want to continue? [y/N] " yorn
|
||||||
|
if [[ "$yorn" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
||||||
|
echo -e "\nDropping autogen retention policy."
|
||||||
|
if docker exec -t so-influxdb influx -format json -ssl -unsafeSsl -execute "drop retention policy autogen on telegraf"; then
|
||||||
|
echo -e "\nAutogen retention policy dropped from InfluxDb."
|
||||||
|
else
|
||||||
|
echo -e "\nSomething went wrong dropping then autogen retention policy from InfluxDB. Please verify that the so-influxdb Docker container is running, and check the log at /opt/so/log/influxdb/influxdb.log for any details."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\nExiting as requested."
|
||||||
|
fi
|
||||||
@@ -8,9 +8,9 @@ fi
|
|||||||
|
|
||||||
echo "This tool will update a manager's IP address to the new IP assigned to the management network interface."
|
echo "This tool will update a manager's IP address to the new IP assigned to the management network interface."
|
||||||
|
|
||||||
echo
|
echo ""
|
||||||
echo "WARNING: This tool is still undergoing testing, use at your own risk!"
|
echo "WARNING: This tool is still undergoing testing, use at your own risk!"
|
||||||
echo
|
echo ""
|
||||||
|
|
||||||
if [ -z "$OLD_IP" ]; then
|
if [ -z "$OLD_IP" ]; then
|
||||||
OLD_IP=$(lookup_pillar "managerip")
|
OLD_IP=$(lookup_pillar "managerip")
|
||||||
@@ -39,9 +39,9 @@ fi
|
|||||||
|
|
||||||
echo "About to change old IP $OLD_IP to new IP $NEW_IP."
|
echo "About to change old IP $OLD_IP to new IP $NEW_IP."
|
||||||
|
|
||||||
echo
|
echo ""
|
||||||
read -n 1 -p "Would you like to continue? (y/N) " CONTINUE
|
read -n 1 -p "Would you like to continue? (y/N) " CONTINUE
|
||||||
echo
|
echo ""
|
||||||
|
|
||||||
if [ "$CONTINUE" == "y" ]; then
|
if [ "$CONTINUE" == "y" ]; then
|
||||||
for file in $(grep -rlI $OLD_IP /opt/so/saltstack /etc); do
|
for file in $(grep -rlI $OLD_IP /opt/so/saltstack /etc); do
|
||||||
@@ -49,6 +49,11 @@ if [ "$CONTINUE" == "y" ]; then
|
|||||||
sed -i "s|$OLD_IP|$NEW_IP|g" $file
|
sed -i "s|$OLD_IP|$NEW_IP|g" $file
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "Granting MySQL root user permissions on $NEW_IP"
|
||||||
|
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'$NEW_IP' IDENTIFIED BY '$(lookup_pillar_secret 'mysql')' WITH GRANT OPTION;" &> /dev/null
|
||||||
|
echo "Removing MySQL root user from $OLD_IP"
|
||||||
|
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "DROP USER 'root'@'$OLD_IP';" &> /dev/null
|
||||||
|
|
||||||
echo "The IP has been changed from $OLD_IP to $NEW_IP."
|
echo "The IP has been changed from $OLD_IP to $NEW_IP."
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -23,7 +23,9 @@
|
|||||||
KIBANA_HOST={{ MANAGER }}
|
KIBANA_HOST={{ MANAGER }}
|
||||||
KSO_PORT=5601
|
KSO_PORT=5601
|
||||||
OUTFILE="saved_objects.ndjson"
|
OUTFILE="saved_objects.ndjson"
|
||||||
curl -s -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -XPOST -L $KIBANA_HOST:$KSO_PORT/api/saved_objects/_export -d '{ "type": [ "index-pattern", "config", "visualization", "dashboard", "search" ], "excludeExportDetails": false }' > $OUTFILE
|
|
||||||
|
SESSIONCOOKIE=$({{ ELASTICCURL }} -c - -X GET http://$KIBANA_HOST:$KSO_PORT/ | grep sid | awk '{print $7}')
|
||||||
|
{{ ELASTICCURL }} -b "sid=$SESSIONCOOKIE" -s -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -XPOST -L $KIBANA_HOST:$KSO_PORT/api/saved_objects/_export -d '{ "type": [ "index-pattern", "config", "visualization", "dashboard", "search" ], "excludeExportDetails": false }' > $OUTFILE
|
||||||
|
|
||||||
# Clean up using PLACEHOLDER
|
# Clean up using PLACEHOLDER
|
||||||
sed -i "s/$KIBANA_HOST/PLACEHOLDER/g" $OUTFILE
|
sed -i "s/$KIBANA_HOST/PLACEHOLDER/g" $OUTFILE
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -17,42 +17,14 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
usage() {
|
echo $banner
|
||||||
echo "Usage: $0 <user-name>"
|
echo "Running kibana.so_savedobjects_defaults Salt state to restore default saved objects."
|
||||||
echo ""
|
printf "This could take a while if another Salt job is running. \nRun this command with --force to stop all Salt jobs before proceeding.\n"
|
||||||
echo "Enables or disables a user in Fleet"
|
echo $banner
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
if [ "$1" = "--force" ]; then
|
||||||
usage
|
printf "\nForce-stopping all Salt jobs before proceeding\n\n"
|
||||||
|
salt-call saltutil.kill_all_jobs
|
||||||
fi
|
fi
|
||||||
|
|
||||||
USER=$1
|
salt-call state.apply kibana.so_savedobjects_defaults -linfo queue=True
|
||||||
|
|
||||||
MYSQL_PASS=$(lookup_pillar_secret mysql)
|
|
||||||
FLEET_IP=$(lookup_pillar fleet_ip)
|
|
||||||
FLEET_USER=$USER
|
|
||||||
|
|
||||||
case "${2^^}" in
|
|
||||||
FALSE | NO | 0)
|
|
||||||
FLEET_STATUS=0
|
|
||||||
;;
|
|
||||||
TRUE | YES | 1)
|
|
||||||
FLEET_STATUS=1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PASS fleet -e \
|
|
||||||
"UPDATE users SET enabled=$FLEET_STATUS WHERE username='$FLEET_USER'" 2>&1)
|
|
||||||
|
|
||||||
if [[ $? -eq 0 ]]; then
|
|
||||||
echo "Successfully updated user in Fleet"
|
|
||||||
else
|
|
||||||
echo "Failed to update user in Fleet"
|
|
||||||
echo $resp
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %}
|
||||||
wait_for_web_response "http://localhost:5601/app/kibana" "Elastic"
|
wait_for_web_response "http://localhost:5601/app/kibana" "Elastic" 300 "{{ ELASTICCURL }}"
|
||||||
## This hackery will be removed if using Elastic Auth ##
|
## This hackery will be removed if using Elastic Auth ##
|
||||||
|
|
||||||
# Let's snag a cookie from Kibana
|
# Let's snag a cookie from Kibana
|
||||||
THECOOKIE=$(curl -c - -X GET http://localhost:5601/ | grep sid | awk '{print $7}')
|
SESSIONCOOKIE=$({{ ELASTICCURL }} -c - -X GET http://localhost:5601/ | grep sid | awk '{print $7}')
|
||||||
|
|
||||||
# Disable certain Features from showing up in the Kibana UI
|
# Disable certain Features from showing up in the Kibana UI
|
||||||
echo
|
echo
|
||||||
echo "Setting up default Space:"
|
echo "Setting up default Space:"
|
||||||
curl -b "sid=$THECOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["ml","enterpriseSearch","siem","logs","infrastructure","apm","uptime","monitoring","stackAlerts","actions","fleet"]} ' >> /opt/so/log/kibana/misc.log
|
{% if HIGHLANDER %}
|
||||||
|
{{ ELASTICCURL }} -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["enterpriseSearch"]} ' >> /opt/so/log/kibana/misc.log
|
||||||
|
{% else %}
|
||||||
|
{{ ELASTICCURL }} -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["ml","enterpriseSearch","siem","logs","infrastructure","apm","uptime","monitoring","stackAlerts","actions","fleet"]} ' >> /opt/so/log/kibana/misc.log
|
||||||
|
{% endif %}
|
||||||
echo
|
echo
|
||||||
303
salt/common/tools/sbin/so-learn
Executable file
303
salt/common/tools/sbin/so-learn
Executable file
@@ -0,0 +1,303 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from itertools import chain
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
import textwrap
|
||||||
|
import yaml
|
||||||
|
import multiprocessing
|
||||||
|
import docker
|
||||||
|
import pty
|
||||||
|
|
||||||
|
minion_pillar_dir = '/opt/so/saltstack/local/pillar/minions'
|
||||||
|
so_status_conf = '/opt/so/conf/so-status/so-status.conf'
|
||||||
|
proc: subprocess.CompletedProcess = None
|
||||||
|
|
||||||
|
# Temp store of modules, will likely be broken out into salt
|
||||||
|
def get_learn_modules():
|
||||||
|
return {
|
||||||
|
'logscan': { 'cpu_period': get_cpu_period(fraction=0.25), 'enabled': False, 'description': 'Scan log files against pre-trained models to alert on anomalies.' }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_cpu_period(fraction: float):
|
||||||
|
multiplier = 10000
|
||||||
|
|
||||||
|
num_cores = multiprocessing.cpu_count()
|
||||||
|
if num_cores <= 2:
|
||||||
|
fraction = 1.
|
||||||
|
|
||||||
|
num_used_cores = int(num_cores * fraction)
|
||||||
|
cpu_period = num_used_cores * multiplier
|
||||||
|
return cpu_period
|
||||||
|
|
||||||
|
|
||||||
|
def sigint_handler(*_):
|
||||||
|
print('Exiting gracefully on Ctrl-C')
|
||||||
|
if proc is not None: proc.send_signal(signal.SIGINT)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def find_minion_pillar() -> str:
|
||||||
|
regex = '^.*_(manager|managersearch|standalone|import|eval)\.sls$'
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for root, _, files in os.walk(minion_pillar_dir):
|
||||||
|
for f_minion_id in files:
|
||||||
|
if re.search(regex, f_minion_id):
|
||||||
|
result.append(os.path.join(root, f_minion_id))
|
||||||
|
|
||||||
|
if len(result) == 0:
|
||||||
|
print('Could not find manager-type pillar (eval, standalone, manager, managersearch, import). Are you running this script on the manager?', file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
elif len(result) > 1:
|
||||||
|
res_str = ', '.join(f'\"{result}\"')
|
||||||
|
print('(This should not happen, the system is in an error state if you see this message.)\n', file=sys.stderr)
|
||||||
|
print('More than one manager-type pillar exists, minion id\'s listed below:', file=sys.stderr)
|
||||||
|
print(f' {res_str}', file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
else:
|
||||||
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
|
def read_pillar(pillar: str):
|
||||||
|
try:
|
||||||
|
with open(pillar, 'r') as pillar_file:
|
||||||
|
loaded_yaml = yaml.safe_load(pillar_file.read())
|
||||||
|
if loaded_yaml is None:
|
||||||
|
print(f'Could not parse {pillar}', file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
return loaded_yaml
|
||||||
|
except:
|
||||||
|
print(f'Could not open {pillar}', file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
|
||||||
|
def write_pillar(pillar: str, content: dict):
|
||||||
|
try:
|
||||||
|
with open(pillar, 'w') as pillar_file:
|
||||||
|
yaml.dump(content, pillar_file, default_flow_style=False)
|
||||||
|
except:
|
||||||
|
print(f'Could not open {pillar}', file=sys.stderr)
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
|
||||||
|
def mod_so_status(action: str, item: str):
|
||||||
|
with open(so_status_conf, 'a+') as conf:
|
||||||
|
conf.seek(0)
|
||||||
|
containers = conf.readlines()
|
||||||
|
|
||||||
|
if f'so-{item}\n' in containers:
|
||||||
|
if action == 'remove': containers.remove(f'so-{item}\n')
|
||||||
|
if action == 'add': pass
|
||||||
|
else:
|
||||||
|
if action == 'remove': pass
|
||||||
|
if action == 'add': containers.append(f'so-{item}\n')
|
||||||
|
|
||||||
|
[containers.remove(c_name) for c_name in containers if c_name == '\n'] # remove extra newlines
|
||||||
|
|
||||||
|
conf.seek(0)
|
||||||
|
conf.truncate(0)
|
||||||
|
conf.writelines(containers)
|
||||||
|
|
||||||
|
|
||||||
|
def create_pillar_if_not_exist(pillar:str, content: dict):
|
||||||
|
pillar_dict = content
|
||||||
|
|
||||||
|
if pillar_dict.get('learn', {}).get('modules') is None:
|
||||||
|
pillar_dict['learn'] = {}
|
||||||
|
pillar_dict['learn']['modules'] = get_learn_modules()
|
||||||
|
content.update()
|
||||||
|
write_pillar(pillar, content)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def salt_call(module: str):
|
||||||
|
salt_cmd = ['salt-call', 'state.apply', '-l', 'quiet', f'learn.{module}', 'queue=True']
|
||||||
|
|
||||||
|
print(f' Applying salt state for {module} module...')
|
||||||
|
proc = subprocess.run(salt_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
return_code = proc.returncode
|
||||||
|
if return_code != 0:
|
||||||
|
print(f' [ERROR] Failed to apply salt state for {module} module.')
|
||||||
|
|
||||||
|
return return_code
|
||||||
|
|
||||||
|
|
||||||
|
def pull_image(module: str):
|
||||||
|
container_basename = f'so-{module}'
|
||||||
|
|
||||||
|
client = docker.from_env()
|
||||||
|
image_list = client.images.list(filters={ 'dangling': False })
|
||||||
|
tag_list = list(chain.from_iterable(list(map(lambda x: x.attrs.get('RepoTags'), image_list))))
|
||||||
|
basename_match = list(filter(lambda x: f'{container_basename}' in x, tag_list))
|
||||||
|
local_registry_match = list(filter(lambda x: ':5000' in x, basename_match))
|
||||||
|
|
||||||
|
if len(local_registry_match) == 0:
|
||||||
|
print(f'Pulling and verifying missing image for {module} (may take several minutes) ...')
|
||||||
|
pull_command = ['so-image-pull', '--quiet', container_basename]
|
||||||
|
|
||||||
|
proc = subprocess.run(pull_command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
return_code = proc.returncode
|
||||||
|
if return_code != 0:
|
||||||
|
print(f'[ERROR] Failed to pull image so-{module}, skipping state.')
|
||||||
|
else:
|
||||||
|
return_code = 0
|
||||||
|
return return_code
|
||||||
|
|
||||||
|
|
||||||
|
def apply(module_list: List):
|
||||||
|
return_code = 0
|
||||||
|
for module in module_list:
|
||||||
|
salt_ret = salt_call(module)
|
||||||
|
# Only update return_code if the command returned a non-zero return
|
||||||
|
if salt_ret != 0:
|
||||||
|
return_code = salt_ret
|
||||||
|
|
||||||
|
return return_code
|
||||||
|
|
||||||
|
|
||||||
|
def check_apply(args: dict):
|
||||||
|
if args.apply:
|
||||||
|
print('Configuration updated. Applying changes:')
|
||||||
|
return apply(args.modules)
|
||||||
|
else:
|
||||||
|
message = 'Configuration updated. Would you like to apply your changes now? (y/N) '
|
||||||
|
answer = input(message)
|
||||||
|
while answer.lower() not in [ 'y', 'n', '' ]:
|
||||||
|
answer = input(message)
|
||||||
|
if answer.lower() in [ 'n', '' ]:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print('Applying changes:')
|
||||||
|
return apply(args.modules)
|
||||||
|
|
||||||
|
|
||||||
|
def enable_disable_modules(args, enable: bool):
|
||||||
|
pillar_modules = args.pillar_dict.get('learn', {}).get('modules')
|
||||||
|
pillar_mod_names = args.pillar_dict.get('learn', {}).get('modules').keys()
|
||||||
|
|
||||||
|
action_str = 'add' if enable else 'remove'
|
||||||
|
|
||||||
|
if 'all' in args.modules:
|
||||||
|
for module, details in pillar_modules.items():
|
||||||
|
details['enabled'] = enable
|
||||||
|
mod_so_status(action_str, module)
|
||||||
|
if enable: pull_image(module)
|
||||||
|
args.pillar_dict.update()
|
||||||
|
write_pillar(args.pillar, args.pillar_dict)
|
||||||
|
else:
|
||||||
|
write_needed = False
|
||||||
|
for module in args.modules:
|
||||||
|
if module in pillar_mod_names:
|
||||||
|
if pillar_modules[module]['enabled'] == enable:
|
||||||
|
state_str = 'enabled' if enable else 'disabled'
|
||||||
|
print(f'{module} module already {state_str}.', file=sys.stderr)
|
||||||
|
else:
|
||||||
|
if enable and pull_image(module) != 0:
|
||||||
|
continue
|
||||||
|
pillar_modules[module]['enabled'] = enable
|
||||||
|
mod_so_status(action_str, module)
|
||||||
|
write_needed = True
|
||||||
|
if write_needed:
|
||||||
|
args.pillar_dict.update()
|
||||||
|
write_pillar(args.pillar, args.pillar_dict)
|
||||||
|
|
||||||
|
cmd_ret = check_apply(args)
|
||||||
|
return cmd_ret
|
||||||
|
|
||||||
|
|
||||||
|
def enable_modules(args):
|
||||||
|
enable_disable_modules(args, enable=True)
|
||||||
|
|
||||||
|
|
||||||
|
def disable_modules(args):
|
||||||
|
enable_disable_modules(args, enable=False)
|
||||||
|
|
||||||
|
|
||||||
|
def list_modules(*_):
|
||||||
|
print('Available ML modules:')
|
||||||
|
for module, details in get_learn_modules().items():
|
||||||
|
print(f' - { module } : {details["description"]}')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
beta_str = 'BETA - SUBJECT TO CHANGE\n'
|
||||||
|
|
||||||
|
apply_help='After ACTION the chosen modules, apply any necessary salt states.'
|
||||||
|
enable_apply_help = apply_help.replace('ACTION', 'enabling')
|
||||||
|
disable_apply_help = apply_help.replace('ACTION', 'disabling')
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print('You must run this script as root', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main_parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
subcommand_desc = textwrap.dedent(
|
||||||
|
"""\
|
||||||
|
enable Enable one or more ML modules.
|
||||||
|
disable Disable one or more ML modules.
|
||||||
|
list List all available ML modules.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
subparsers = main_parser.add_subparsers(title='commands', description=subcommand_desc, metavar='', dest='command')
|
||||||
|
|
||||||
|
module_help_str = 'One or more ML modules, which can be listed using \'so-learn list\'. Use the keyword \'all\' to apply the action to all available modules.'
|
||||||
|
|
||||||
|
enable = subparsers.add_parser('enable')
|
||||||
|
enable.set_defaults(func=enable_modules)
|
||||||
|
enable.add_argument('modules', metavar='ML_MODULE', nargs='+', help=module_help_str)
|
||||||
|
enable.add_argument('--apply', action='store_const', const=True, required=False, help=enable_apply_help)
|
||||||
|
|
||||||
|
disable = subparsers.add_parser('disable')
|
||||||
|
disable.set_defaults(func=disable_modules)
|
||||||
|
disable.add_argument('modules', metavar='ML_MODULE', nargs='+', help=module_help_str)
|
||||||
|
disable.add_argument('--apply', action='store_const', const=True, required=False, help=disable_apply_help)
|
||||||
|
|
||||||
|
list = subparsers.add_parser('list')
|
||||||
|
list.set_defaults(func=list_modules)
|
||||||
|
|
||||||
|
args = main_parser.parse_args(sys.argv[1:])
|
||||||
|
args.pillar = find_minion_pillar()
|
||||||
|
args.pillar_dict = create_pillar_if_not_exist(args.pillar, read_pillar(args.pillar))
|
||||||
|
|
||||||
|
if hasattr(args, 'func'):
|
||||||
|
exit_code = args.func(args)
|
||||||
|
else:
|
||||||
|
if args.command is None:
|
||||||
|
print(beta_str)
|
||||||
|
main_parser.print_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
23
salt/common/tools/sbin/so-airgap-hotfixdownload → salt/common/tools/sbin/so-pcap-export
Normal file → Executable file
23
salt/common/tools/sbin/so-airgap-hotfixdownload → salt/common/tools/sbin/so-pcap-export
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
#
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -15,19 +15,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# Get the latest code
|
if [ $# -lt 2 ]; then
|
||||||
rm -rf /tmp/sohotfix
|
echo "Usage: $0 <steno-query> Output-Filename"
|
||||||
mkdir -p /tmp/sohotfix
|
|
||||||
cd /tmp/sohotfix
|
|
||||||
git clone https://github.com/Security-Onion-Solutions/securityonion
|
|
||||||
if [ ! -d "/tmp/sohotfix/securityonion" ]; then
|
|
||||||
echo "I was unable to get the latest code. Check your internet and try again."
|
|
||||||
exit 1
|
exit 1
|
||||||
else
|
|
||||||
echo "Looks like we have the code lets create the tarball."
|
|
||||||
cd /tmp/sohotfix/securityonion
|
|
||||||
tar cvf /tmp/sohotfix/sohotfix.tar HOTFIX VERSION salt pillar
|
|
||||||
echo ""
|
|
||||||
echo "Copy /tmp/sohotfix/sohotfix.tar to portable media and then copy it to your airgap manager."
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
docker exec -it so-sensoroni scripts/stenoquery.sh "$1" -w /nsm/pcapout/$2.pcap
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "If successful, the output was written to: /nsm/pcapout/$2.pcap"
|
||||||
22
salt/common/tools/sbin/so-playbook-import
Executable file
22
salt/common/tools/sbin/so-playbook-import
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
ENABLEPLAY=${1:-False}
|
||||||
|
|
||||||
|
docker exec so-soctopus /usr/local/bin/python -c "import playbook; print(playbook.play_import($ENABLEPLAY))"
|
||||||
@@ -22,5 +22,5 @@ salt-call state.apply playbook.db_init,playbook,playbook.automation_user_create
|
|||||||
/usr/sbin/so-soctopus-restart
|
/usr/sbin/so-soctopus-restart
|
||||||
|
|
||||||
echo "Importing Plays - this will take some time...."
|
echo "Importing Plays - this will take some time...."
|
||||||
wait 5
|
sleep 5
|
||||||
/usr/sbin/so-playbook-ruleupdate
|
/usr/sbin/so-playbook-ruleupdate
|
||||||
@@ -17,67 +17,101 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
#check_boss_raid() {
|
appliance_check() {
|
||||||
# BOSSBIN=/opt/boss/mvcli
|
{%- if salt['grains.get']('sosmodel', '') %}
|
||||||
# BOSSRC=$($BOSSBIN info -o vd | grep functional)
|
APPLIANCE=1
|
||||||
#
|
{%- if grains['sosmodel'] in ['SO2AMI01', 'SO2GCI01', 'SO2AZI01'] %}
|
||||||
# if [[ $BOSSRC ]]; then
|
exit 0
|
||||||
# # Raid is good
|
{%- endif %}
|
||||||
# BOSSRAID=0
|
DUDEYOUGOTADELL=$(dmidecode |grep Dell)
|
||||||
# else
|
if [[ -n $DUDEYOUGOTADELL ]]; then
|
||||||
# BOSSRAID=1
|
APPTYPE=dell
|
||||||
# fi
|
|
||||||
#}
|
|
||||||
|
|
||||||
check_lsi_raid() {
|
|
||||||
# For use for LSI on Ubuntu
|
|
||||||
#MEGA=/opt/MegaRAID/MegeCli/MegaCli64
|
|
||||||
#LSIRC=$($MEGA -LDInfo -Lall -aALL | grep Optimal)
|
|
||||||
# Open Source Centos
|
|
||||||
MEGA=/opt/mega/megasasctl
|
|
||||||
LSIRC=$($MEGA | grep optimal)
|
|
||||||
|
|
||||||
if [[ $LSIRC ]]; then
|
|
||||||
# Raid is good
|
|
||||||
LSIRAID=0
|
|
||||||
else
|
else
|
||||||
LSIRAID=1
|
APPTYPE=sm
|
||||||
|
fi
|
||||||
|
mkdir -p /opt/so/log/raid
|
||||||
|
|
||||||
|
{%- else %}
|
||||||
|
echo "This is not an appliance"
|
||||||
|
exit 0
|
||||||
|
{%- endif %}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_nsm_raid() {
|
||||||
|
PERCCLI=$(/opt/raidtools/perccli/perccli64 /c0/v0 show|grep RAID|grep Optl)
|
||||||
|
MEGACTL=$(/opt/raidtools/megasasctl |grep optimal)
|
||||||
|
|
||||||
|
if [[ $APPLIANCE == '1' ]]; then
|
||||||
|
if [[ -n $PERCCLI ]]; then
|
||||||
|
HWRAID=0
|
||||||
|
elif [[ -n $MEGACTL ]]; then
|
||||||
|
HWRAID=0
|
||||||
|
else
|
||||||
|
HWRAID=1
|
||||||
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_boss_raid() {
|
||||||
|
MVCLI=$(/usr/local/bin/mvcli info -o vd |grep status |grep functional)
|
||||||
|
|
||||||
|
if [[ -n $DUDEYOUGOTADELL ]]; then
|
||||||
|
if [[ -n $MVCLI ]]; then
|
||||||
|
BOSSRAID=0
|
||||||
|
else
|
||||||
|
BOSSRAID=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
check_software_raid() {
|
check_software_raid() {
|
||||||
|
if [[ -n $DUDEYOUGOTADELL ]]; then
|
||||||
SWRC=$(grep "_" /proc/mdstat)
|
SWRC=$(grep "_" /proc/mdstat)
|
||||||
|
|
||||||
if [[ $SWRC ]]; then
|
if [[ -n $SWRC ]]; then
|
||||||
# RAID is failed in some way
|
# RAID is failed in some way
|
||||||
SWRAID=1
|
SWRAID=1
|
||||||
else
|
else
|
||||||
SWRAID=0
|
SWRAID=0
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# This script checks raid status if you use SO appliances
|
# This script checks raid status if you use SO appliances
|
||||||
|
|
||||||
# See if this is an appliance
|
# See if this is an appliance
|
||||||
|
|
||||||
|
appliance_check
|
||||||
|
check_nsm_raid
|
||||||
|
check_boss_raid
|
||||||
{%- if salt['grains.get']('sosmodel', '') %}
|
{%- if salt['grains.get']('sosmodel', '') %}
|
||||||
mkdir -p /opt/so/log/raid
|
|
||||||
{%- if grains['sosmodel'] in ['SOSMN', 'SOSSNNV'] %}
|
{%- if grains['sosmodel'] in ['SOSMN', 'SOSSNNV'] %}
|
||||||
#check_boss_raid
|
|
||||||
check_software_raid
|
check_software_raid
|
||||||
#echo "osraid=$BOSSRAID nsmraid=$SWRAID" > /opt/so/log/raid/status.log
|
|
||||||
echo "osraid=1 nsmraid=$SWRAID" > /opt/so/log/raid/status.log
|
|
||||||
{%- elif grains['sosmodel'] in ['SOS1000F', 'SOS1000', 'SOSSN7200', 'SOS10K', 'SOS4000'] %}
|
|
||||||
#check_boss_raid
|
|
||||||
check_lsi_raid
|
|
||||||
#echo "osraid=$BOSSRAID nsmraid=$LSIRAID" > /opt/so/log/raid/status.log
|
|
||||||
echo "osraid=1 nsmraid=$LSIRAID" > /opt/so/log/raid/status.log
|
|
||||||
{%- else %}
|
|
||||||
exit 0
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- else %}
|
|
||||||
exit 0
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
if [[ -n $SWRAID ]]; then
|
||||||
|
if [[ $SWRAID == '0' && $BOSSRAID == '0' ]]; then
|
||||||
|
RAIDSTATUS=0
|
||||||
|
else
|
||||||
|
RAIDSTATUS=1
|
||||||
|
fi
|
||||||
|
elif [[ -n $DUDEYOUGOTADELL ]]; then
|
||||||
|
if [[ $BOSSRAID == '0' && $HWRAID == '0' ]]; then
|
||||||
|
RAIDSTATUS=0
|
||||||
|
else
|
||||||
|
RAIDSTATUS=1
|
||||||
|
fi
|
||||||
|
elif [[ "$APPTYPE" == 'sm' ]]; then
|
||||||
|
if [[ -n "$HWRAID" ]]; then
|
||||||
|
RAIDSTATUS=0
|
||||||
|
else
|
||||||
|
RAIDSTATUS=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "nsmraid=$RAIDSTATUS" > /opt/so/log/raid/status.log
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,4 @@
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
docker exec -it so-redis redis-cli llen logstash:unparsed
|
docker exec so-redis redis-cli llen logstash:unparsed
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ def main():
|
|||||||
enabled_list.set_defaults(func=list_enabled_rules)
|
enabled_list.set_defaults(func=list_enabled_rules)
|
||||||
|
|
||||||
|
|
||||||
search_term_help='A quoted regex search term (ex: "\$EXTERNAL_NET")'
|
search_term_help='A properly escaped regex search term (ex: "\\\$EXTERNAL_NET")'
|
||||||
replace_term_help='The text to replace the search term with'
|
replace_term_help='The text to replace the search term with'
|
||||||
|
|
||||||
# Modify actions
|
# Modify actions
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
got_root() {
|
|
||||||
|
|
||||||
# Make sure you are root
|
. /usr/sbin/so-common
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
|
||||||
echo "This script must be run using sudo!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
argstr=""
|
||||||
|
for arg in "$@"; do
|
||||||
|
argstr="${argstr} \"${arg}\""
|
||||||
|
done
|
||||||
|
|
||||||
got_root
|
docker exec so-idstools /bin/bash -c "cd /opt/so/idstools/etc && idstools-rulecat --force ${argstr}"
|
||||||
docker exec so-idstools /bin/bash -c "cd /opt/so/idstools/etc && idstools-rulecat $1"
|
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ if [ $CURRENT_TIME -ge $((SYSTEM_START_TIME+$UPTIME_REQ)) ]; then
|
|||||||
log "last highstate completed at `date -d @$LAST_HIGHSTATE_END`" I
|
log "last highstate completed at `date -d @$LAST_HIGHSTATE_END`" I
|
||||||
log "checking if any jobs are running" I
|
log "checking if any jobs are running" I
|
||||||
logCmd "salt-call --local saltutil.running" I
|
logCmd "salt-call --local saltutil.running" I
|
||||||
|
log "ensure salt.minion-state-apply-test is enabled" I
|
||||||
|
logCmd "salt-call state.enable salt.minion-state-apply-test" I
|
||||||
|
log "ensure highstate is enabled" I
|
||||||
|
logCmd "salt-call state.enable highstate" I
|
||||||
log "killing all salt-minion processes" I
|
log "killing all salt-minion processes" I
|
||||||
logCmd "pkill -9 -ef /usr/bin/salt-minion" I
|
logCmd "pkill -9 -ef /usr/bin/salt-minion" I
|
||||||
log "starting salt-minion service" I
|
log "starting salt-minion service" I
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ TESTPCAP=$2
|
|||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "Usage: $0 <CustomRule> <TargetPCAP>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "==============="
|
echo "==============="
|
||||||
echo "Running all.rules and $TESTRULE against the following pcap: $TESTPCAP"
|
echo "Running all.rules and $TESTRULE against the following pcap: $TESTPCAP"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ if [[ $# -lt 1 ]]; then
|
|||||||
echo "Usage: $0 <pcap-sample(s)>"
|
echo "Usage: $0 <pcap-sample(s)>"
|
||||||
echo
|
echo
|
||||||
echo "All PCAPs must be placed in the /opt/so/samples directory unless replaying"
|
echo "All PCAPs must be placed in the /opt/so/samples directory unless replaying"
|
||||||
echo "a sample pcap that is included in the so-tcpreplay image. Those PCAP sampes"
|
echo "a sample pcap that is included in the so-tcpreplay image. Those PCAP samples"
|
||||||
echo "are located in the /opt/samples directory inside of the image."
|
echo "are located in the /opt/samples directory inside of the image."
|
||||||
echo
|
echo
|
||||||
echo "Customer provided PCAP example:"
|
echo "Customer provided PCAP example:"
|
||||||
|
|||||||
@@ -41,10 +41,7 @@ if [[ $? == 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
read -rs THEHIVE_PASS
|
read -rs THEHIVE_PASS
|
||||||
|
|
||||||
if ! check_password "$THEHIVE_PASS"; then
|
check_password_and_exit "$THEHIVE_PASS"
|
||||||
echo "Password is invalid. Please exclude single quotes, double quotes and backslashes from the password."
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create new user in TheHive
|
# Create new user in TheHive
|
||||||
resp=$(curl -sk -XPOST -H "Authorization: Bearer $THEHIVE_KEY" -H "Content-Type: application/json" -L "https://$THEHVIE_API_URL/user" -d "{\"login\" : \"$THEHIVE_USER\",\"name\" : \"$THEHIVE_USER\",\"roles\" : [\"read\",\"alert\",\"write\",\"admin\"],\"preferences\" : \"{}\",\"password\" : \"$THEHIVE_PASS\"}")
|
resp=$(curl -sk -XPOST -H "Authorization: Bearer $THEHIVE_KEY" -H "Content-Type: application/json" -L "https://$THEHVIE_API_URL/user" -d "{\"login\" : \"$THEHIVE_USER\",\"name\" : \"$THEHIVE_USER\",\"roles\" : [\"read\",\"alert\",\"write\",\"admin\"],\"preferences\" : \"{}\",\"password\" : \"$THEHIVE_PASS\"}")
|
||||||
|
|||||||
57
salt/common/tools/sbin/so-thehive-user-update
Executable file
57
salt/common/tools/sbin/so-thehive-user-update
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <user-name>"
|
||||||
|
echo ""
|
||||||
|
echo "Update password for an existing TheHive user. The new password will be read from STDIN."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
USER=$1
|
||||||
|
|
||||||
|
THEHIVE_KEY=$(lookup_pillar hivekey)
|
||||||
|
THEHVIE_API_URL="$(lookup_pillar url_base)/thehive/api"
|
||||||
|
THEHIVE_USER=$USER
|
||||||
|
|
||||||
|
# Read password for new user from stdin
|
||||||
|
test -t 0
|
||||||
|
if [[ $? == 0 ]]; then
|
||||||
|
echo "Enter new password:"
|
||||||
|
fi
|
||||||
|
read -rs THEHIVE_PASS
|
||||||
|
|
||||||
|
if ! check_password "$THEHIVE_PASS"; then
|
||||||
|
echo "Password is invalid. Please exclude single quotes, double quotes, dollar signs, and backslashes from the password."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Change password for user in TheHive
|
||||||
|
resp=$(curl -sk -XPOST -H "Authorization: Bearer $THEHIVE_KEY" -H "Content-Type: application/json" -L "https://$THEHVIE_API_URL/user/${THEHIVE_USER}/password/set" -d "{\"password\" : \"$THEHIVE_PASS\"}")
|
||||||
|
if [[ -z "$resp" ]]; then
|
||||||
|
echo "Successfully updated TheHive user password"
|
||||||
|
else
|
||||||
|
echo "Unable to update TheHive user password"
|
||||||
|
echo $resp
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
@@ -18,11 +18,17 @@
|
|||||||
|
|
||||||
source $(dirname $0)/so-common
|
source $(dirname $0)/so-common
|
||||||
|
|
||||||
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
DEFAULT_ROLE=analyst
|
||||||
echo "Usage: $0 <list|add|update|enable|disable|validate|valemail|valpass> [email]"
|
|
||||||
|
if [[ $# -lt 1 || $# -gt 3 ]]; then
|
||||||
|
echo "Usage: $0 <operation> [email] [role]"
|
||||||
|
echo ""
|
||||||
|
echo " where <operation> is one of the following:"
|
||||||
echo ""
|
echo ""
|
||||||
echo " list: Lists all user email addresses currently defined in the identity system"
|
echo " list: Lists all user email addresses currently defined in the identity system"
|
||||||
echo " add: Adds a new user to the identity system; requires 'email' parameter"
|
echo " add: Adds a new user to the identity system; requires 'email' parameter, while 'role' parameter is optional and defaults to $DEFAULT_ROLE"
|
||||||
|
echo " addrole: Grants a role to an existing user; requires 'email' and 'role' parameters"
|
||||||
|
echo " delrole: Removes a role from an existing user; requires 'email' and 'role' parameters"
|
||||||
echo " update: Updates a user's password; requires 'email' parameter"
|
echo " update: Updates a user's password; requires 'email' parameter"
|
||||||
echo " enable: Enables a user; requires 'email' parameter"
|
echo " enable: Enables a user; requires 'email' parameter"
|
||||||
echo " disable: Disables a user; requires 'email' parameter"
|
echo " disable: Disables a user; requires 'email' parameter"
|
||||||
@@ -36,13 +42,25 @@ fi
|
|||||||
|
|
||||||
operation=$1
|
operation=$1
|
||||||
email=$2
|
email=$2
|
||||||
|
role=$3
|
||||||
|
|
||||||
kratosUrl=${KRATOS_URL:-http://127.0.0.1:4434}
|
kratosUrl=${KRATOS_URL:-http://127.0.0.1:4434}
|
||||||
databasePath=${KRATOS_DB_PATH:-/opt/so/conf/kratos/db/db.sqlite}
|
databasePath=${KRATOS_DB_PATH:-/opt/so/conf/kratos/db/db.sqlite}
|
||||||
argon2Iterations=${ARGON2_ITERATIONS:-3}
|
bcryptRounds=${BCRYPT_ROUNDS:-12}
|
||||||
argon2Memory=${ARGON2_MEMORY:-14}
|
elasticUsersFile=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users}
|
||||||
argon2Parallelism=${ARGON2_PARALLELISM:-2}
|
elasticRolesFile=${ELASTIC_ROLES_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users_roles}
|
||||||
argon2HashSize=${ARGON2_HASH_SIZE:-32}
|
socRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_users_roles}
|
||||||
|
esUID=${ELASTIC_UID:-930}
|
||||||
|
esGID=${ELASTIC_GID:-930}
|
||||||
|
soUID=${SOCORE_UID:-939}
|
||||||
|
soGID=${SOCORE_GID:-939}
|
||||||
|
|
||||||
|
function lock() {
|
||||||
|
# Obtain file descriptor lock
|
||||||
|
exec 99>/var/tmp/so-user.lock || fail "Unable to create lock descriptor; if the system was not shutdown gracefully you may need to remove /var/tmp/so-user.lock manually."
|
||||||
|
flock -w 10 99 || fail "Another process is using so-user; if the system was not shutdown gracefully you may need to remove /var/tmp/so-user.lock manually."
|
||||||
|
trap 'rm -f /var/tmp/so-user.lock' EXIT
|
||||||
|
}
|
||||||
|
|
||||||
function fail() {
|
function fail() {
|
||||||
msg=$1
|
msg=$1
|
||||||
@@ -58,7 +76,7 @@ function require() {
|
|||||||
|
|
||||||
# Verify this environment is capable of running this script
|
# Verify this environment is capable of running this script
|
||||||
function verifyEnvironment() {
|
function verifyEnvironment() {
|
||||||
require "argon2"
|
require "htpasswd"
|
||||||
require "jq"
|
require "jq"
|
||||||
require "curl"
|
require "curl"
|
||||||
require "openssl"
|
require "openssl"
|
||||||
@@ -72,7 +90,7 @@ function findIdByEmail() {
|
|||||||
email=$1
|
email=$1
|
||||||
|
|
||||||
response=$(curl -Ss -L ${kratosUrl}/identities)
|
response=$(curl -Ss -L ${kratosUrl}/identities)
|
||||||
identityId=$(echo "${response}" | jq ".[] | select(.verifiable_addresses[0].value == \"$email\") | .id")
|
identityId=$(echo "${response}" | jq -r ".[] | select(.verifiable_addresses[0].value == \"$email\") | .id")
|
||||||
echo $identityId
|
echo $identityId
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,20 +99,36 @@ function validatePassword() {
|
|||||||
|
|
||||||
len=$(expr length "$password")
|
len=$(expr length "$password")
|
||||||
if [[ $len -lt 6 ]]; then
|
if [[ $len -lt 6 ]]; then
|
||||||
echo "Password does not meet the minimum requirements"
|
fail "Password does not meet the minimum requirements"
|
||||||
exit 2
|
|
||||||
fi
|
fi
|
||||||
|
if [[ $len -gt 72 ]]; then
|
||||||
|
fail "Password is too long (max: 72)"
|
||||||
|
fi
|
||||||
|
check_password_and_exit "$password"
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateEmail() {
|
function validateEmail() {
|
||||||
email=$1
|
email=$1
|
||||||
# (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
|
# (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
|
||||||
if [[ ! "$email" =~ ^[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}$ ]]; then
|
if [[ ! "$email" =~ ^[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}$ ]]; then
|
||||||
echo "Email address is invalid"
|
fail "Email address is invalid"
|
||||||
exit 3
|
fi
|
||||||
|
|
||||||
|
if [[ "$email" =~ [A-Z] ]]; then
|
||||||
|
fail "Email addresses cannot contain uppercase letters"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hashPassword() {
|
||||||
|
password=$1
|
||||||
|
|
||||||
|
passwordHash=$(echo "${password}" | htpasswd -niBC $bcryptRounds SOUSER)
|
||||||
|
passwordHash=$(echo "$passwordHash" | cut -c 11-)
|
||||||
|
passwordHash="\$2a${passwordHash}" # still waiting for https://github.com/elastic/elasticsearch/issues/51132
|
||||||
|
echo "$passwordHash"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function updatePassword() {
|
function updatePassword() {
|
||||||
identityId=$1
|
identityId=$1
|
||||||
|
|
||||||
@@ -109,26 +143,229 @@ function updatePassword() {
|
|||||||
validatePassword "$password"
|
validatePassword "$password"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $identityId ]]; then
|
if [[ -n "$identityId" ]]; then
|
||||||
# Generate password hash
|
# Generate password hash
|
||||||
salt=$(openssl rand -hex 8)
|
passwordHash=$(hashPassword "$password")
|
||||||
passwordHash=$(echo "${password}" | argon2 ${salt} -id -t $argon2Iterations -m $argon2Memory -p $argon2Parallelism -l $argon2HashSize -e)
|
|
||||||
|
|
||||||
# Update DB with new hash
|
# Update DB with new hash
|
||||||
echo "update identity_credentials set config=CAST('{\"hashed_password\":\"${passwordHash}\"}' as BLOB) where identity_id=${identityId};" | sqlite3 "$databasePath"
|
echo "update identity_credentials set config=CAST('{\"hashed_password\":\"$passwordHash\"}' as BLOB) where identity_id='${identityId}';" | sqlite3 "$databasePath"
|
||||||
[[ $? != 0 ]] && fail "Unable to update password"
|
[[ $? != 0 ]] && fail "Unable to update password"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createFile() {
|
||||||
|
filename=$1
|
||||||
|
uid=$2
|
||||||
|
gid=$3
|
||||||
|
|
||||||
|
mkdir -p $(dirname "$filename")
|
||||||
|
truncate -s 0 "$filename"
|
||||||
|
chmod 600 "$filename"
|
||||||
|
chown "${uid}:${gid}" "$filename"
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureRoleFileExists() {
|
||||||
|
if [[ ! -f "$socRolesFile" || ! -s "$socRolesFile" ]]; then
|
||||||
|
# Generate the new users file
|
||||||
|
rolesTmpFile="${socRolesFile}.tmp"
|
||||||
|
createFile "$rolesTmpFile" "$soUID" "$soGID"
|
||||||
|
|
||||||
|
if [[ -f "$databasePath" ]]; then
|
||||||
|
echo "Migrating roles to new file: $socRolesFile"
|
||||||
|
|
||||||
|
echo "select 'superuser:' || id from identities;" | sqlite3 "$databasePath" \
|
||||||
|
>> "$rolesTmpFile"
|
||||||
|
[[ $? != 0 ]] && fail "Unable to read identities from database"
|
||||||
|
|
||||||
|
echo "The following users have all been migrated with the super user role:"
|
||||||
|
cat "${rolesTmpFile}"
|
||||||
|
else
|
||||||
|
echo "Database file does not exist yet, installation is likely not yet complete."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "$socRolesFile" ]]; then
|
||||||
|
echo "Removing invalid roles directory created by Docker"
|
||||||
|
rm -fr "$socRolesFile"
|
||||||
|
fi
|
||||||
|
mv "${rolesTmpFile}" "${socRolesFile}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncElasticSystemUser() {
|
||||||
|
json=$1
|
||||||
|
userid=$2
|
||||||
|
usersFile=$3
|
||||||
|
|
||||||
|
user=$(echo "$json" | jq -r ".local.users.$userid.user")
|
||||||
|
pass=$(echo "$json" | jq -r ".local.users.$userid.pass")
|
||||||
|
|
||||||
|
[[ -z "$user" || -z "$pass" ]] && fail "Elastic auth credentials for system user '$userid' are missing"
|
||||||
|
hash=$(hashPassword "$pass")
|
||||||
|
|
||||||
|
echo "${user}:${hash}" >> "$usersFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncElasticSystemRole() {
|
||||||
|
json=$1
|
||||||
|
userid=$2
|
||||||
|
role=$3
|
||||||
|
rolesFile=$4
|
||||||
|
|
||||||
|
user=$(echo "$json" | jq -r ".local.users.$userid.user")
|
||||||
|
|
||||||
|
[[ -z "$user" ]] && fail "Elastic auth credentials for system user '$userid' are missing"
|
||||||
|
|
||||||
|
echo "${role}:${user}" >> "$rolesFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncElastic() {
|
||||||
|
echo "Syncing users and roles between SOC and Elastic..."
|
||||||
|
|
||||||
|
usersTmpFile="${elasticUsersFile}.tmp"
|
||||||
|
createFile "${usersTmpFile}" "$esUID" "$esGID"
|
||||||
|
rolesTmpFile="${elasticRolesFile}.tmp"
|
||||||
|
createFile "${rolesTmpFile}" "$esUID" "$esGID"
|
||||||
|
|
||||||
|
authPillarJson=$(lookup_salt_value "auth" "elasticsearch" "pillar" "json")
|
||||||
|
|
||||||
|
syncElasticSystemUser "$authPillarJson" "so_elastic_user" "$usersTmpFile"
|
||||||
|
syncElasticSystemUser "$authPillarJson" "so_kibana_user" "$usersTmpFile"
|
||||||
|
syncElasticSystemUser "$authPillarJson" "so_logstash_user" "$usersTmpFile"
|
||||||
|
syncElasticSystemUser "$authPillarJson" "so_beats_user" "$usersTmpFile"
|
||||||
|
syncElasticSystemUser "$authPillarJson" "so_monitor_user" "$usersTmpFile"
|
||||||
|
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_elastic_user" "superuser" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_kibana_user" "superuser" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_logstash_user" "superuser" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_beats_user" "superuser" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_monitor_user" "remote_monitoring_collector" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_monitor_user" "remote_monitoring_agent" "$rolesTmpFile"
|
||||||
|
syncElasticSystemRole "$authPillarJson" "so_monitor_user" "monitoring_user" "$rolesTmpFile"
|
||||||
|
|
||||||
|
if [[ -f "$databasePath" && -f "$socRolesFile" ]]; then
|
||||||
|
# Append the SOC users
|
||||||
|
echo "select '{\"user\":\"' || ici.identifier || '\", \"data\":' || ic.config || '}'" \
|
||||||
|
"from identity_credential_identifiers ici, identity_credentials ic, identities i " \
|
||||||
|
"where " \
|
||||||
|
" ici.identity_credential_id=ic.id " \
|
||||||
|
" and ic.identity_id=i.id " \
|
||||||
|
" and instr(ic.config, 'hashed_password') " \
|
||||||
|
" and i.state == 'active' " \
|
||||||
|
"order by ici.identifier;" | \
|
||||||
|
sqlite3 "$databasePath" | \
|
||||||
|
jq -r '.user + ":" + .data.hashed_password' \
|
||||||
|
>> "$usersTmpFile"
|
||||||
|
[[ $? != 0 ]] && fail "Unable to read credential hashes from database"
|
||||||
|
|
||||||
|
# Append the user roles
|
||||||
|
while IFS="" read -r rolePair || [ -n "$rolePair" ]; do
|
||||||
|
userId=$(echo "$rolePair" | cut -d: -f2)
|
||||||
|
role=$(echo "$rolePair" | cut -d: -f1)
|
||||||
|
echo "select '$role:' || ici.identifier " \
|
||||||
|
"from identity_credential_identifiers ici, identity_credentials ic " \
|
||||||
|
"where ici.identity_credential_id=ic.id and ic.identity_id = '$userId';" | \
|
||||||
|
sqlite3 "$databasePath" >> "$rolesTmpFile"
|
||||||
|
done < "$socRolesFile"
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "Database file or soc roles file does not exist yet, skipping users export"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -s "${usersTmpFile}" ]]; then
|
||||||
|
mv "${usersTmpFile}" "${elasticUsersFile}"
|
||||||
|
mv "${rolesTmpFile}" "${elasticRolesFile}"
|
||||||
|
|
||||||
|
if [[ -z "$SKIP_STATE_APPLY" ]]; then
|
||||||
|
echo "Elastic state will be re-applied to affected minions. This may take several minutes..."
|
||||||
|
echo "Applying elastic state to elastic minions at $(date)" >> /opt/so/log/soc/sync.log 2>&1
|
||||||
|
salt -C 'G@role:so-standalone or G@role:so-eval or G@role:so-import or G@role:so-manager or G@role:so-managersearch or G@role:so-node or G@role:so-heavynode' state.apply elasticsearch queue=True >> /opt/so/log/soc/sync.log 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Newly generated users/roles files are incomplete; aborting."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncAll() {
|
||||||
|
ensureRoleFileExists
|
||||||
|
|
||||||
|
# Check if a sync is needed. Sync is not needed if the following are true:
|
||||||
|
# - user database entries are all older than the elastic users file
|
||||||
|
# - soc roles file last modify date is older than the elastic roles file
|
||||||
|
if [[ -z "$FORCE_SYNC" && -f "$databasePath" && -f "$elasticUsersFile" ]]; then
|
||||||
|
usersFileAgeSecs=$(echo $(($(date +%s) - $(date +%s -r "$elasticUsersFile"))))
|
||||||
|
staleCount=$(echo "select count(*) from identity_credentials where updated_at >= Datetime('now', '-${usersFileAgeSecs} seconds');" \
|
||||||
|
| sqlite3 "$databasePath")
|
||||||
|
if [[ "$staleCount" == "0" && "$elasticRolesFile" -nt "$socRolesFile" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
syncElastic
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
function listUsers() {
|
function listUsers() {
|
||||||
response=$(curl -Ss -L ${kratosUrl}/identities)
|
response=$(curl -Ss -L ${kratosUrl}/identities)
|
||||||
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
||||||
|
|
||||||
echo "${response}" | jq -r ".[] | .verifiable_addresses[0].value" | sort
|
users=$(echo "${response}" | jq -r ".[] | .verifiable_addresses[0].value" | sort)
|
||||||
|
for user in $users; do
|
||||||
|
roles=$(grep "$user" "$elasticRolesFile" | cut -d: -f1 | tr '\n' ' ')
|
||||||
|
echo "$user: $roles"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function addUserRole() {
|
||||||
|
email=$1
|
||||||
|
role=$2
|
||||||
|
|
||||||
|
adjustUserRole "$email" "$role" "add"
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteUserRole() {
|
||||||
|
email=$1
|
||||||
|
role=$2
|
||||||
|
|
||||||
|
adjustUserRole "$email" "$role" "del"
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjustUserRole() {
|
||||||
|
email=$1
|
||||||
|
role=$2
|
||||||
|
op=$3
|
||||||
|
|
||||||
|
identityId=$(findIdByEmail "$email")
|
||||||
|
[[ ${identityId} == "" ]] && fail "User not found"
|
||||||
|
|
||||||
|
ensureRoleFileExists
|
||||||
|
|
||||||
|
filename="$socRolesFile"
|
||||||
|
hasRole=0
|
||||||
|
grep "$role:" "$socRolesFile" | grep -q "$identityId" && hasRole=1
|
||||||
|
if [[ "$op" == "add" ]]; then
|
||||||
|
if [[ "$hasRole" == "1" ]]; then
|
||||||
|
echo "User '$email' already has the role: $role"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo "$role:$identityId" >> "$filename"
|
||||||
|
fi
|
||||||
|
elif [[ "$op" == "del" ]]; then
|
||||||
|
if [[ "$hasRole" -ne 1 ]]; then
|
||||||
|
fail "User '$email' does not have the role: $role"
|
||||||
|
else
|
||||||
|
sed "/^$role:$identityId\$/d" "$filename" > "$filename.tmp"
|
||||||
|
cat "$filename".tmp > "$filename"
|
||||||
|
rm -f "$filename".tmp
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "Unsupported role adjustment operation: $op"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function createUser() {
|
function createUser() {
|
||||||
email=$1
|
email=$1
|
||||||
|
role=$2
|
||||||
|
|
||||||
now=$(date -u +%FT%TZ)
|
now=$(date -u +%FT%TZ)
|
||||||
addUserJson=$(cat <<EOF
|
addUserJson=$(cat <<EOF
|
||||||
@@ -142,16 +379,30 @@ EOF
|
|||||||
response=$(curl -Ss -L ${kratosUrl}/identities -d "$addUserJson")
|
response=$(curl -Ss -L ${kratosUrl}/identities -d "$addUserJson")
|
||||||
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
||||||
|
|
||||||
identityId=$(echo "${response}" | jq ".id")
|
identityId=$(echo "${response}" | jq -r ".id")
|
||||||
if [[ ${identityId} == "null" ]]; then
|
if [[ "${identityId}" == "null" ]]; then
|
||||||
code=$(echo "${response}" | jq ".error.code")
|
code=$(echo "${response}" | jq ".error.code")
|
||||||
[[ "${code}" == "409" ]] && fail "User already exists"
|
[[ "${code}" == "409" ]] && fail "User already exists"
|
||||||
|
|
||||||
reason=$(echo "${response}" | jq ".error.message")
|
reason=$(echo "${response}" | jq ".error.message")
|
||||||
[[ $? == 0 ]] && fail "Unable to add user: ${reason}"
|
[[ $? == 0 ]] && fail "Unable to add user: ${reason}"
|
||||||
|
else
|
||||||
|
updatePassword "$identityId"
|
||||||
|
addUserRole "$email" "$role"
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
updatePassword $identityId
|
function migrateLockedUsers() {
|
||||||
|
# This is a migration function to convert locked users from prior to 2.3.90
|
||||||
|
# to inactive users using the newer Kratos functionality. This should only
|
||||||
|
# find locked users once.
|
||||||
|
lockedEmails=$(curl -s http://localhost:4434/identities | jq -r '.[] | select(.traits.status == "locked") | .traits.email')
|
||||||
|
if [[ -n "$lockedEmails" ]]; then
|
||||||
|
echo "Disabling locked users..."
|
||||||
|
for email in $lockedEmails; do
|
||||||
|
updateStatus "$email" locked
|
||||||
|
done
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateStatus() {
|
function updateStatus() {
|
||||||
@@ -164,24 +415,18 @@ function updateStatus() {
|
|||||||
response=$(curl -Ss -L "${kratosUrl}/identities/$identityId")
|
response=$(curl -Ss -L "${kratosUrl}/identities/$identityId")
|
||||||
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
||||||
|
|
||||||
oldConfig=$(echo "select config from identity_credentials where identity_id=${identityId};" | sqlite3 "$databasePath")
|
schemaId=$(echo "$response" | jq -r .schema_id)
|
||||||
|
|
||||||
|
# Capture traits and remove obsolete 'status' trait if exists
|
||||||
|
traitBlock=$(echo "$response" | jq -c .traits | sed -re 's/,?"status":".*?"//')
|
||||||
|
|
||||||
|
state="active"
|
||||||
if [[ "$status" == "locked" ]]; then
|
if [[ "$status" == "locked" ]]; then
|
||||||
config=$(echo $oldConfig | sed -e 's/hashed/locked/')
|
state="inactive"
|
||||||
echo "update identity_credentials set config=CAST('${config}' as BLOB) where identity_id=${identityId};" | sqlite3 "$databasePath"
|
|
||||||
[[ $? != 0 ]] && fail "Unable to lock credential record"
|
|
||||||
|
|
||||||
echo "delete from sessions where identity_id=${identityId};" | sqlite3 "$databasePath"
|
|
||||||
[[ $? != 0 ]] && fail "Unable to invalidate sessions"
|
|
||||||
else
|
|
||||||
config=$(echo $oldConfig | sed -e 's/locked/hashed/')
|
|
||||||
echo "update identity_credentials set config=CAST('${config}' as BLOB) where identity_id=${identityId};" | sqlite3 "$databasePath"
|
|
||||||
[[ $? != 0 ]] && fail "Unable to unlock credential record"
|
|
||||||
fi
|
fi
|
||||||
|
body="{ \"schema_id\": \"$schemaId\", \"state\": \"$state\", \"traits\": $traitBlock }"
|
||||||
updatedJson=$(echo "$response" | jq ".traits.status = \"$status\" | del(.verifiable_addresses) | del(.id) | del(.schema_url)")
|
response=$(curl -fSsL -XPUT "${kratosUrl}/identities/$identityId" -d "$body")
|
||||||
response=$(curl -Ss -XPUT -L ${kratosUrl}/identities/$identityId -d "$updatedJson")
|
[[ $? != 0 ]] && fail "Unable to update user"
|
||||||
[[ $? != 0 ]] && fail "Unable to mark user as locked"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUser() {
|
function updateUser() {
|
||||||
@@ -190,7 +435,7 @@ function updateUser() {
|
|||||||
identityId=$(findIdByEmail "$email")
|
identityId=$(findIdByEmail "$email")
|
||||||
[[ ${identityId} == "" ]] && fail "User not found"
|
[[ ${identityId} == "" ]] && fail "User not found"
|
||||||
|
|
||||||
updatePassword $identityId
|
updatePassword "$identityId"
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUser() {
|
function deleteUser() {
|
||||||
@@ -201,6 +446,11 @@ function deleteUser() {
|
|||||||
|
|
||||||
response=$(curl -Ss -XDELETE -L "${kratosUrl}/identities/$identityId")
|
response=$(curl -Ss -XDELETE -L "${kratosUrl}/identities/$identityId")
|
||||||
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
[[ $? != 0 ]] && fail "Unable to communicate with Kratos"
|
||||||
|
|
||||||
|
rolesTmpFile="${socRolesFile}.tmp"
|
||||||
|
createFile "$rolesTmpFile" "$soUID" "$soGID"
|
||||||
|
grep -v "$identityId" "$socRolesFile" > "$rolesTmpFile"
|
||||||
|
mv "$rolesTmpFile" "$socRolesFile"
|
||||||
}
|
}
|
||||||
|
|
||||||
case "${operation}" in
|
case "${operation}" in
|
||||||
@@ -208,12 +458,14 @@ case "${operation}" in
|
|||||||
verifyEnvironment
|
verifyEnvironment
|
||||||
[[ "$email" == "" ]] && fail "Email address must be provided"
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
validateEmail "$email"
|
validateEmail "$email"
|
||||||
updatePassword
|
updatePassword
|
||||||
createUser "$email"
|
createUser "$email" "${role:-$DEFAULT_ROLE}"
|
||||||
|
syncAll
|
||||||
echo "Successfully added new user to SOC"
|
echo "Successfully added new user to SOC"
|
||||||
check_container thehive && echo $password | so-thehive-user-add "$email"
|
check_container thehive && echo "$password" | so-thehive-user-add "$email"
|
||||||
check_container fleet && echo $password | so-fleet-user-add "$email"
|
check_container fleet && echo "$password" | so-fleet-user-add "$email"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"list")
|
"list")
|
||||||
@@ -221,11 +473,38 @@ case "${operation}" in
|
|||||||
listUsers
|
listUsers
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
"addrole")
|
||||||
|
verifyEnvironment
|
||||||
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
[[ "$role" == "" ]] && fail "Role must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
|
validateEmail "$email"
|
||||||
|
if addUserRole "$email" "$role"; then
|
||||||
|
syncElastic
|
||||||
|
echo "Successfully added role to user"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"delrole")
|
||||||
|
verifyEnvironment
|
||||||
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
[[ "$role" == "" ]] && fail "Role must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
|
validateEmail "$email"
|
||||||
|
deleteUserRole "$email" "$role"
|
||||||
|
syncElastic
|
||||||
|
echo "Successfully removed role from user"
|
||||||
|
;;
|
||||||
|
|
||||||
"update")
|
"update")
|
||||||
verifyEnvironment
|
verifyEnvironment
|
||||||
[[ "$email" == "" ]] && fail "Email address must be provided"
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
updateUser "$email"
|
updateUser "$email"
|
||||||
|
syncAll
|
||||||
echo "Successfully updated user"
|
echo "Successfully updated user"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@@ -233,30 +512,41 @@ case "${operation}" in
|
|||||||
verifyEnvironment
|
verifyEnvironment
|
||||||
[[ "$email" == "" ]] && fail "Email address must be provided"
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
updateStatus "$email" 'active'
|
updateStatus "$email" 'active'
|
||||||
|
syncAll
|
||||||
echo "Successfully enabled user"
|
echo "Successfully enabled user"
|
||||||
check_container thehive && so-thehive-user-enable "$email" true
|
check_container thehive && so-thehive-user-enable "$email" true
|
||||||
check_container fleet && so-fleet-user-enable "$email" true
|
echo "Fleet user will need to be recreated manually with so-fleet-user-add"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"disable")
|
"disable")
|
||||||
verifyEnvironment
|
verifyEnvironment
|
||||||
[[ "$email" == "" ]] && fail "Email address must be provided"
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
updateStatus "$email" 'locked'
|
updateStatus "$email" 'locked'
|
||||||
|
syncAll
|
||||||
echo "Successfully disabled user"
|
echo "Successfully disabled user"
|
||||||
check_container thehive && so-thehive-user-enable "$email" false
|
check_container thehive && so-thehive-user-enable "$email" false
|
||||||
check_container fleet && so-fleet-user-enable "$email" false
|
check_container fleet && so-fleet-user-delete "$email"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"delete")
|
"delete")
|
||||||
verifyEnvironment
|
verifyEnvironment
|
||||||
[[ "$email" == "" ]] && fail "Email address must be provided"
|
[[ "$email" == "" ]] && fail "Email address must be provided"
|
||||||
|
|
||||||
|
lock
|
||||||
deleteUser "$email"
|
deleteUser "$email"
|
||||||
|
syncAll
|
||||||
echo "Successfully deleted user"
|
echo "Successfully deleted user"
|
||||||
check_container thehive && so-thehive-user-enable "$email" false
|
check_container thehive && so-thehive-user-enable "$email" false
|
||||||
check_container fleet && so-fleet-user-enable "$email" false
|
check_container fleet && so-fleet-user-delete "$email"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"sync")
|
||||||
|
lock
|
||||||
|
syncAll
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"validate")
|
"validate")
|
||||||
@@ -275,6 +565,11 @@ case "${operation}" in
|
|||||||
echo "Password is acceptable"
|
echo "Password is acceptable"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
"migrate")
|
||||||
|
migrateLockedUsers
|
||||||
|
echo "User migration complete"
|
||||||
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
fail "Unsupported operation: $operation"
|
fail "Unsupported operation: $operation"
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -20,13 +19,8 @@ echo "Starting to check for yara rule updates at $(date)..."
|
|||||||
|
|
||||||
output_dir="/opt/so/saltstack/default/salt/strelka/rules"
|
output_dir="/opt/so/saltstack/default/salt/strelka/rules"
|
||||||
mkdir -p $output_dir
|
mkdir -p $output_dir
|
||||||
|
|
||||||
repos="$output_dir/repos.txt"
|
repos="$output_dir/repos.txt"
|
||||||
ignorefile="$output_dir/ignore.txt"
|
|
||||||
|
|
||||||
deletecounter=0
|
|
||||||
newcounter=0
|
newcounter=0
|
||||||
updatecounter=0
|
|
||||||
|
|
||||||
{% if ISAIRGAP is sameas true %}
|
{% if ISAIRGAP is sameas true %}
|
||||||
|
|
||||||
@@ -35,58 +29,21 @@ echo "Airgap mode enabled."
|
|||||||
clone_dir="/nsm/repo/rules/strelka"
|
clone_dir="/nsm/repo/rules/strelka"
|
||||||
repo_name="signature-base"
|
repo_name="signature-base"
|
||||||
mkdir -p /opt/so/saltstack/default/salt/strelka/rules/signature-base
|
mkdir -p /opt/so/saltstack/default/salt/strelka/rules/signature-base
|
||||||
|
# Ensure a copy of the license is available for the rules
|
||||||
[ -f $clone_dir/LICENSE ] && cp $clone_dir/$repo_name/LICENSE $output_dir/$repo_name
|
[ -f $clone_dir/LICENSE ] && cp $clone_dir/$repo_name/LICENSE $output_dir/$repo_name
|
||||||
|
|
||||||
# Copy over rules
|
# Copy over rules
|
||||||
for i in $(find $clone_dir/yara -name "*.yar*"); do
|
for i in $(find $clone_dir/yara -name "*.yar*"); do
|
||||||
rule_name=$(echo $i | awk -F '/' '{print $NF}')
|
rule_name=$(echo $i | awk -F '/' '{print $NF}')
|
||||||
repo_sum=$(sha256sum $i | awk '{print $1}')
|
echo "Adding rule: $rule_name..."
|
||||||
|
|
||||||
# Check rules against those in ignore list -- don't copy if ignored.
|
|
||||||
if ! grep -iq $rule_name $ignorefile; then
|
|
||||||
existing_rules=$(find $output_dir/$repo_name/ -name $rule_name | wc -l)
|
|
||||||
|
|
||||||
# For existing rules, check to see if they need to be updated, by comparing checksums
|
|
||||||
if [ $existing_rules -gt 0 ];then
|
|
||||||
local_sum=$(sha256sum $output_dir/$repo_name/$rule_name | awk '{print $1}')
|
|
||||||
if [ "$repo_sum" != "$local_sum" ]; then
|
|
||||||
echo "Checksums do not match!"
|
|
||||||
echo "Updating $rule_name..."
|
|
||||||
cp $i $output_dir/$repo_name;
|
|
||||||
((updatecounter++))
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# If rule doesn't exist already, we'll add it
|
|
||||||
echo "Adding new rule: $rule_name..."
|
|
||||||
cp $i $output_dir/$repo_name
|
cp $i $output_dir/$repo_name
|
||||||
((newcounter++))
|
((newcounter++))
|
||||||
fi
|
|
||||||
fi;
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check to see if we have any old rules that need to be removed
|
|
||||||
for i in $(find $output_dir/$repo_name -name "*.yar*" | awk -F '/' '{print $NF}'); do
|
|
||||||
is_repo_rule=$(find $clone_dir -name "$i" | wc -l)
|
|
||||||
if [ $is_repo_rule -eq 0 ]; then
|
|
||||||
echo "Could not find $i in source $repo_name repo...removing from $output_dir/$repo_name..."
|
|
||||||
rm $output_dir/$repo_name/$i
|
|
||||||
((deletecounter++))
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
||||||
if [ "$newcounter" -gt 0 ];then
|
if [ "$newcounter" -gt 0 ];then
|
||||||
echo "$newcounter new rules added."
|
echo "$newcounter rules added."
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$updatecounter" -gt 0 ];then
|
|
||||||
echo "$updatecounter rules updated."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$deletecounter" -gt 0 ];then
|
|
||||||
echo "$deletecounter rules removed because they were deprecated or don't exist in the source repo."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -99,50 +56,21 @@ if [ "$gh_status" == "200" ] || [ "$gh_status" == "301" ]; then
|
|||||||
if ! $(echo "$repo" | grep -qE '^#'); then
|
if ! $(echo "$repo" | grep -qE '^#'); then
|
||||||
# Remove old repo if existing bc of previous error condition or unexpected disruption
|
# Remove old repo if existing bc of previous error condition or unexpected disruption
|
||||||
repo_name=`echo $repo | awk -F '/' '{print $NF}'`
|
repo_name=`echo $repo | awk -F '/' '{print $NF}'`
|
||||||
[ -d $repo_name ] && rm -rf $repo_name
|
[ -d $output_dir/$repo_name ] && rm -rf $output_dir/$repo_name
|
||||||
|
|
||||||
# Clone repo and make appropriate directories for rules
|
# Clone repo and make appropriate directories for rules
|
||||||
|
|
||||||
git clone $repo $clone_dir/$repo_name
|
git clone $repo $clone_dir/$repo_name
|
||||||
echo "Analyzing rules from $clone_dir/$repo_name..."
|
echo "Analyzing rules from $clone_dir/$repo_name..."
|
||||||
mkdir -p $output_dir/$repo_name
|
mkdir -p $output_dir/$repo_name
|
||||||
|
# Ensure a copy of the license is available for the rules
|
||||||
[ -f $clone_dir/$repo_name/LICENSE ] && cp $clone_dir/$repo_name/LICENSE $output_dir/$repo_name
|
[ -f $clone_dir/$repo_name/LICENSE ] && cp $clone_dir/$repo_name/LICENSE $output_dir/$repo_name
|
||||||
|
|
||||||
# Copy over rules
|
# Copy over rules
|
||||||
for i in $(find $clone_dir/$repo_name -name "*.yar*"); do
|
for i in $(find $clone_dir/$repo_name -name "*.yar*"); do
|
||||||
rule_name=$(echo $i | awk -F '/' '{print $NF}')
|
rule_name=$(echo $i | awk -F '/' '{print $NF}')
|
||||||
repo_sum=$(sha256sum $i | awk '{print $1}')
|
echo "Adding rule: $rule_name..."
|
||||||
|
|
||||||
# Check rules against those in ignore list -- don't copy if ignored.
|
|
||||||
if ! grep -iq $rule_name $ignorefile; then
|
|
||||||
existing_rules=$(find $output_dir/$repo_name/ -name $rule_name | wc -l)
|
|
||||||
|
|
||||||
# For existing rules, check to see if they need to be updated, by comparing checksums
|
|
||||||
if [ $existing_rules -gt 0 ];then
|
|
||||||
local_sum=$(sha256sum $output_dir/$repo_name/$rule_name | awk '{print $1}')
|
|
||||||
if [ "$repo_sum" != "$local_sum" ]; then
|
|
||||||
echo "Checksums do not match!"
|
|
||||||
echo "Updating $rule_name..."
|
|
||||||
cp $i $output_dir/$repo_name;
|
|
||||||
((updatecounter++))
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# If rule doesn't exist already, we'll add it
|
|
||||||
echo "Adding new rule: $rule_name..."
|
|
||||||
cp $i $output_dir/$repo_name
|
cp $i $output_dir/$repo_name
|
||||||
((newcounter++))
|
((newcounter++))
|
||||||
fi
|
|
||||||
fi;
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check to see if we have any old rules that need to be removed
|
|
||||||
for i in $(find $output_dir/$repo_name -name "*.yar*" | awk -F '/' '{print $NF}'); do
|
|
||||||
is_repo_rule=$(find $clone_dir/$repo_name -name "$i" | wc -l)
|
|
||||||
if [ $is_repo_rule -eq 0 ]; then
|
|
||||||
echo "Could not find $i in source $repo_name repo...removing from $output_dir/$repo_name..."
|
|
||||||
rm $output_dir/$repo_name/$i
|
|
||||||
((deletecounter++))
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
rm -rf $clone_dir/$repo_name
|
rm -rf $clone_dir/$repo_name
|
||||||
fi
|
fi
|
||||||
@@ -151,15 +79,7 @@ if [ "$gh_status" == "200" ] || [ "$gh_status" == "301" ]; then
|
|||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
||||||
if [ "$newcounter" -gt 0 ];then
|
if [ "$newcounter" -gt 0 ];then
|
||||||
echo "$newcounter new rules added."
|
echo "$newcounter rules added."
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$updatecounter" -gt 0 ];then
|
|
||||||
echo "$updatecounter rules updated."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$deletecounter" -gt 0 ];then
|
|
||||||
echo "$deletecounter rules removed because they were deprecated or don't exist in the source repo."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ zeek_logs_enabled() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
whiptail_manager_adv_service_zeeklogs() {
|
whiptail_manager_adv_service_zeeklogs() {
|
||||||
BLOGS=$(whiptail --title "Security Onion Setup" --checklist "Please Select Logs to Send:" 24 78 12 \
|
BLOGS=$(whiptail --title "so-zeek-logs" --checklist "Please Select Logs to Send:" 24 78 12 \
|
||||||
"conn" "Connection Logging" ON \
|
"conn" "Connection Logging" ON \
|
||||||
"dce_rpc" "RPC Logs" ON \
|
"dce_rpc" "RPC Logs" ON \
|
||||||
"dhcp" "DHCP Logs" ON \
|
"dhcp" "DHCP Logs" ON \
|
||||||
"dhcpv6" "DHCP IPv6 Logs" ON \
|
|
||||||
"dnp3" "DNP3 Logs" ON \
|
"dnp3" "DNP3 Logs" ON \
|
||||||
"dns" "DNS Logs" ON \
|
"dns" "DNS Logs" ON \
|
||||||
"dpd" "DPD Logs" ON \
|
"dpd" "DPD Logs" ON \
|
||||||
@@ -25,25 +24,20 @@ whiptail_manager_adv_service_zeeklogs() {
|
|||||||
"irc" "IRC Chat Logs" ON \
|
"irc" "IRC Chat Logs" ON \
|
||||||
"kerberos" "Kerberos Logs" ON \
|
"kerberos" "Kerberos Logs" ON \
|
||||||
"modbus" "MODBUS Logs" ON \
|
"modbus" "MODBUS Logs" ON \
|
||||||
"mqtt" "MQTT Logs" ON \
|
|
||||||
"notice" "Zeek Notice Logs" ON \
|
"notice" "Zeek Notice Logs" ON \
|
||||||
"ntlm" "NTLM Logs" ON \
|
"ntlm" "NTLM Logs" ON \
|
||||||
"openvpn" "OPENVPN Logs" ON \
|
|
||||||
"pe" "PE Logs" ON \
|
"pe" "PE Logs" ON \
|
||||||
"radius" "Radius Logs" ON \
|
"radius" "Radius Logs" ON \
|
||||||
"rfb" "RFB Logs" ON \
|
"rfb" "RFB Logs" ON \
|
||||||
"rdp" "RDP Logs" ON \
|
"rdp" "RDP Logs" ON \
|
||||||
"signatures" "Signatures Logs" ON \
|
|
||||||
"sip" "SIP Logs" ON \
|
"sip" "SIP Logs" ON \
|
||||||
"smb_files" "SMB Files Logs" ON \
|
"smb_files" "SMB Files Logs" ON \
|
||||||
"smb_mapping" "SMB Mapping Logs" ON \
|
"smb_mapping" "SMB Mapping Logs" ON \
|
||||||
"smtp" "SMTP Logs" ON \
|
"smtp" "SMTP Logs" ON \
|
||||||
"snmp" "SNMP Logs" ON \
|
"snmp" "SNMP Logs" ON \
|
||||||
"software" "Software Logs" ON \
|
|
||||||
"ssh" "SSH Logs" ON \
|
"ssh" "SSH Logs" ON \
|
||||||
"ssl" "SSL Logs" ON \
|
"ssl" "SSL Logs" ON \
|
||||||
"syslog" "Syslog Logs" ON \
|
"syslog" "Syslog Logs" ON \
|
||||||
"telnet" "Telnet Logs" ON \
|
|
||||||
"tunnel" "Tunnel Logs" ON \
|
"tunnel" "Tunnel Logs" ON \
|
||||||
"weird" "Zeek Weird Logs" ON \
|
"weird" "Zeek Weird Logs" ON \
|
||||||
"mysql" "MySQL Logs" ON \
|
"mysql" "MySQL Logs" ON \
|
||||||
@@ -61,10 +55,10 @@ whiptail_manager_adv_service_zeeklogs
|
|||||||
return_code=$?
|
return_code=$?
|
||||||
case $return_code in
|
case $return_code in
|
||||||
1)
|
1)
|
||||||
whiptail --title "Security Onion Setup" --msgbox "Cancelling. No changes have been made." 8 75
|
whiptail --title "so-zeek-logs" --msgbox "Cancelling. No changes have been made." 8 75
|
||||||
;;
|
;;
|
||||||
255)
|
255)
|
||||||
whiptail --title "Security Onion Setup" --msgbox "Whiptail error occured, exiting." 8 75
|
whiptail --title "so-zeek-logs" --msgbox "Whiptail error occured, exiting." 8 75
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
zeek_logs_enabled
|
zeek_logs_enabled
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ show_stats() {
|
|||||||
echo
|
echo
|
||||||
echo "Average throughput:"
|
echo "Average throughput:"
|
||||||
echo
|
echo
|
||||||
docker exec so-zeek env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/bin:/usr/local/bin:/usr/local/sbin runuser -l zeek -c '/opt/zeek/bin/zeekctl capstats'
|
docker exec so-zeek env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/bin:/usr/local/bin:/usr/local/sbin /opt/zeek/bin/zeekctl capstats
|
||||||
echo
|
echo
|
||||||
echo "Average packet loss:"
|
echo "Average packet loss:"
|
||||||
echo
|
echo
|
||||||
docker exec so-zeek env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/bin:/usr/local/bin:/usr/local/sbin runuser -l zeek -c '/opt/zeek/bin/zeekctl netstats'
|
docker exec so-zeek env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/bin:/usr/local/bin:/usr/local/sbin /opt/zeek/bin/zeekctl netstats
|
||||||
echo
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,83 @@
|
|||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
UPDATE_DIR=/tmp/sogh/securityonion
|
UPDATE_DIR=/tmp/sogh/securityonion
|
||||||
|
DEFAULT_SALT_DIR=/opt/so/saltstack/default
|
||||||
INSTALLEDVERSION=$(cat /etc/soversion)
|
INSTALLEDVERSION=$(cat /etc/soversion)
|
||||||
POSTVERSION=$INSTALLEDVERSION
|
POSTVERSION=$INSTALLEDVERSION
|
||||||
INSTALLEDSALTVERSION=$(salt --versions-report | grep Salt: | awk {'print $2'})
|
INSTALLEDSALTVERSION=$(salt --versions-report | grep Salt: | awk '{print $2}')
|
||||||
BATCHSIZE=5
|
BATCHSIZE=5
|
||||||
SOUP_LOG=/root/soup.log
|
SOUP_LOG=/root/soup.log
|
||||||
|
INFLUXDB_MIGRATION_LOG=/opt/so/log/influxdb/soup_migration.log
|
||||||
WHATWOULDYOUSAYYAHDOHERE=soup
|
WHATWOULDYOUSAYYAHDOHERE=soup
|
||||||
|
whiptail_title='Security Onion UPdater'
|
||||||
|
NOTIFYCUSTOMELASTICCONFIG=false
|
||||||
|
|
||||||
|
check_err() {
|
||||||
|
local exit_code=$1
|
||||||
|
local err_msg="Unhandled error occured, please check $SOUP_LOG for details."
|
||||||
|
|
||||||
|
[[ $ERR_HANDLED == true ]] && exit $exit_code
|
||||||
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
|
printf '%s' "Soup failed with error $exit_code: "
|
||||||
|
case $exit_code in
|
||||||
|
2)
|
||||||
|
echo 'No such file or directory'
|
||||||
|
;;
|
||||||
|
5)
|
||||||
|
echo 'Interrupted system call'
|
||||||
|
;;
|
||||||
|
12)
|
||||||
|
echo 'Out of memory'
|
||||||
|
;;
|
||||||
|
28)
|
||||||
|
echo 'No space left on device'
|
||||||
|
echo 'Likely ran out of space on disk, please review hardware requirements for Security Onion: https://docs.securityonion.net/en/2.3/hardware.html'
|
||||||
|
;;
|
||||||
|
30)
|
||||||
|
echo 'Read-only file system'
|
||||||
|
;;
|
||||||
|
35)
|
||||||
|
echo 'Resource temporarily unavailable'
|
||||||
|
;;
|
||||||
|
64)
|
||||||
|
echo 'Machine is not on the network'
|
||||||
|
;;
|
||||||
|
67)
|
||||||
|
echo 'Link has been severed'
|
||||||
|
;;
|
||||||
|
100)
|
||||||
|
echo 'Network is down'
|
||||||
|
;;
|
||||||
|
101)
|
||||||
|
echo 'Network is unreachable'
|
||||||
|
;;
|
||||||
|
102)
|
||||||
|
echo 'Network reset'
|
||||||
|
;;
|
||||||
|
110)
|
||||||
|
echo 'Connection timed out'
|
||||||
|
;;
|
||||||
|
111)
|
||||||
|
echo 'Connection refused'
|
||||||
|
;;
|
||||||
|
112)
|
||||||
|
echo 'Host is down'
|
||||||
|
;;
|
||||||
|
113)
|
||||||
|
echo 'No route to host'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo 'Unhandled error'
|
||||||
|
echo "$err_msg"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ $exit_code -ge 64 && $exit_code -le 113 ]]; then
|
||||||
|
echo "$err_msg"
|
||||||
|
fi
|
||||||
|
exit $exit_code
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
add_common() {
|
add_common() {
|
||||||
cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
||||||
@@ -35,19 +106,21 @@ add_common() {
|
|||||||
|
|
||||||
airgap_mounted() {
|
airgap_mounted() {
|
||||||
# Let's see if the ISO is already mounted.
|
# Let's see if the ISO is already mounted.
|
||||||
if [ -f /tmp/soagupdate/SecurityOnion/VERSION ]; then
|
if [[ -f /tmp/soagupdate/SecurityOnion/VERSION ]]; then
|
||||||
echo "The ISO is already mounted"
|
echo "The ISO is already mounted"
|
||||||
else
|
else
|
||||||
|
if [[ -z $ISOLOC ]]; then
|
||||||
|
echo "This is airgap. Ask for a location."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Looks like we need access to the upgrade content"
|
cat << EOF
|
||||||
echo ""
|
In order for soup to proceed, the path to the downloaded Security Onion ISO file, or the path to the CD-ROM or equivalent device containing the ISO media must be provided.
|
||||||
echo "If you just copied the .iso file over you can specify the path."
|
For example, if you have copied the new Security Onion ISO file to your home directory, then the path might look like /home/myuser/securityonion-2.x.y.iso.
|
||||||
echo "If you burned the ISO to a disk the standard way you can specify the device."
|
Or, if you have burned the new ISO onto an optical disk then the path might look like /dev/cdrom.
|
||||||
echo "Example: /home/user/securityonion-2.X.0.iso"
|
|
||||||
echo "Example: /dev/sdx1"
|
EOF
|
||||||
echo ""
|
read -rp 'Enter the path to the new Security Onion ISO content: ' ISOLOC
|
||||||
read -p 'Enter the location of the iso: ' ISOLOC
|
fi
|
||||||
if [ -f $ISOLOC ]; then
|
if [[ -f $ISOLOC ]]; then
|
||||||
# Mounting the ISO image
|
# Mounting the ISO image
|
||||||
mkdir -p /tmp/soagupdate
|
mkdir -p /tmp/soagupdate
|
||||||
mount -t iso9660 -o loop $ISOLOC /tmp/soagupdate
|
mount -t iso9660 -o loop $ISOLOC /tmp/soagupdate
|
||||||
@@ -59,10 +132,10 @@ airgap_mounted() {
|
|||||||
else
|
else
|
||||||
echo "ISO has been mounted!"
|
echo "ISO has been mounted!"
|
||||||
fi
|
fi
|
||||||
elif [ -f $ISOLOC/SecurityOnion/VERSION ]; then
|
elif [[ -f $ISOLOC/SecurityOnion/VERSION ]]; then
|
||||||
ln -s $ISOLOC /tmp/soagupdate
|
ln -s $ISOLOC /tmp/soagupdate
|
||||||
echo "Found the update content"
|
echo "Found the update content"
|
||||||
else
|
elif [[ -b $ISOLOC ]]; then
|
||||||
mkdir -p /tmp/soagupdate
|
mkdir -p /tmp/soagupdate
|
||||||
mount $ISOLOC /tmp/soagupdate
|
mount $ISOLOC /tmp/soagupdate
|
||||||
if [ ! -f /tmp/soagupdate/SecurityOnion/VERSION ]; then
|
if [ ! -f /tmp/soagupdate/SecurityOnion/VERSION ]; then
|
||||||
@@ -72,24 +145,28 @@ airgap_mounted() {
|
|||||||
else
|
else
|
||||||
echo "Device has been mounted!"
|
echo "Device has been mounted!"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
echo "Could not find Security Onion ISO content at ${ISOLOC}"
|
||||||
|
echo "Ensure the path you entered is correct, and that you verify the ISO that you downloaded."
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
airgap_update_dockers() {
|
airgap_update_dockers() {
|
||||||
if [ $is_airgap -eq 0 ]; then
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
# Let's copy the tarball
|
# Let's copy the tarball
|
||||||
if [ ! -f $AGDOCKER/registry.tar ]; then
|
if [[ ! -f $AGDOCKER/registry.tar ]]; then
|
||||||
echo "Unable to locate registry. Exiting"
|
echo "Unable to locate registry. Exiting"
|
||||||
exit 1
|
exit 0
|
||||||
else
|
else
|
||||||
echo "Stopping the registry docker"
|
echo "Stopping the registry docker"
|
||||||
docker stop so-dockerregistry
|
docker stop so-dockerregistry
|
||||||
docker rm so-dockerregistry
|
docker rm so-dockerregistry
|
||||||
echo "Copying the new dockers over"
|
echo "Copying the new dockers over"
|
||||||
tar xvf $AGDOCKER/registry.tar -C /nsm/docker-registry/docker
|
tar xvf "$AGDOCKER/registry.tar" -C /nsm/docker-registry/docker
|
||||||
echo "Add Registry back"
|
echo "Add Registry back"
|
||||||
docker load -i $AGDOCKER/registry_image.tar
|
docker load -i "$AGDOCKER/registry_image.tar"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -100,6 +177,63 @@ update_registry() {
|
|||||||
salt-call state.apply registry queue=True
|
salt-call state.apply registry queue=True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_airgap() {
|
||||||
|
# See if this is an airgap install
|
||||||
|
AIRGAP=$(cat /opt/so/saltstack/local/pillar/global.sls | grep airgap: | awk '{print $2}')
|
||||||
|
if [[ "$AIRGAP" == "True" ]]; then
|
||||||
|
is_airgap=0
|
||||||
|
UPDATE_DIR=/tmp/soagupdate/SecurityOnion
|
||||||
|
AGDOCKER=/tmp/soagupdate/docker
|
||||||
|
AGREPO=/tmp/soagupdate/Packages
|
||||||
|
else
|
||||||
|
is_airgap=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# {% raw %}
|
||||||
|
|
||||||
|
check_local_mods() {
|
||||||
|
local salt_local=/opt/so/saltstack/local
|
||||||
|
|
||||||
|
local_mod_arr=()
|
||||||
|
|
||||||
|
while IFS= read -r -d '' local_file; do
|
||||||
|
stripped_path=${local_file#"$salt_local"}
|
||||||
|
default_file="${DEFAULT_SALT_DIR}${stripped_path}"
|
||||||
|
if [[ -f $default_file ]]; then
|
||||||
|
file_diff=$(diff "$default_file" "$local_file" )
|
||||||
|
if [[ $(echo "$file_diff" | grep -c "^<") -gt 0 ]]; then
|
||||||
|
local_mod_arr+=( "$local_file" )
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done< <(find $salt_local -type f -print0)
|
||||||
|
|
||||||
|
if [[ ${#local_mod_arr} -gt 0 ]]; then
|
||||||
|
echo "Potentially breaking changes found in the following files (check ${DEFAULT_SALT_DIR} for original copy):"
|
||||||
|
for file_str in "${local_mod_arr[@]}"; do
|
||||||
|
echo " $file_str"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo "To reference this list later, check $SOUP_LOG"
|
||||||
|
sleep 10
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# {% endraw %}
|
||||||
|
|
||||||
|
check_pillar_items() {
|
||||||
|
local pillar_output=$(salt-call pillar.items --out=json)
|
||||||
|
|
||||||
|
cond=$(jq '.local | has("_errors")' <<< "$pillar_output")
|
||||||
|
if [[ "$cond" == "true" ]]; then
|
||||||
|
printf "\nThere is an issue rendering the manager's pillars. Please correct the issues in the sls files mentioned below before running SOUP again.\n\n"
|
||||||
|
jq '.local._errors[]' <<< "$pillar_output"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
printf "\nThe manager's pillars can be rendered. We can proceed with SOUP.\n\n"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
check_sudoers() {
|
check_sudoers() {
|
||||||
if grep -q "so-setup" /etc/sudoers; then
|
if grep -q "so-setup" /etc/sudoers; then
|
||||||
echo "There is an entry for so-setup in the sudoers file, this can be safely deleted using \"visudo\"."
|
echo "There is an entry for so-setup in the sudoers file, this can be safely deleted using \"visudo\"."
|
||||||
@@ -169,23 +303,31 @@ check_os_updates() {
|
|||||||
OSUPDATES=$(yum -q list updates | wc -l)
|
OSUPDATES=$(yum -q list updates | wc -l)
|
||||||
fi
|
fi
|
||||||
if [[ "$OSUPDATES" -gt 0 ]]; then
|
if [[ "$OSUPDATES" -gt 0 ]]; then
|
||||||
echo $NEEDUPDATES
|
if [[ -z $UNATTENDED ]]; then
|
||||||
|
echo "$NEEDUPDATES"
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Press U to update OS packages (recommended), C to continue without updates, or E to exit: " confirm
|
read -rp "Press U to update OS packages (recommended), C to continue without updates, or E to exit: " confirm
|
||||||
|
|
||||||
if [[ "$confirm" == [cC] ]]; then
|
if [[ "$confirm" == [cC] ]]; then
|
||||||
echo "Continuing without updating packages"
|
echo "Continuing without updating packages"
|
||||||
elif [[ "$confirm" == [uU] ]]; then
|
elif [[ "$confirm" == [uU] ]]; then
|
||||||
echo "Applying Grid Updates"
|
echo "Applying Grid Updates"
|
||||||
salt \* -b 5 state.apply patch.os queue=True
|
update_flag=true
|
||||||
else
|
else
|
||||||
echo "Exiting soup"
|
echo "Exiting soup"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
update_flag=true
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "Looks like you have an updated OS"
|
echo "Looks like you have an updated OS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $update_flag == true ]]; then
|
||||||
|
set +e
|
||||||
|
run_check_net_err "salt '*' -b 5 state.apply patch.os queue=True" 'Could not apply OS updates, please check your network connection.'
|
||||||
|
set -e
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_dockers() {
|
clean_dockers() {
|
||||||
@@ -217,7 +359,7 @@ generate_and_clean_tarballs() {
|
|||||||
local new_version
|
local new_version
|
||||||
new_version=$(cat $UPDATE_DIR/VERSION)
|
new_version=$(cat $UPDATE_DIR/VERSION)
|
||||||
[ -d /opt/so/repo ] || mkdir -p /opt/so/repo
|
[ -d /opt/so/repo ] || mkdir -p /opt/so/repo
|
||||||
tar -czf "/opt/so/repo/$new_version.tar.gz" "$UPDATE_DIR"
|
tar -czf "/opt/so/repo/$new_version.tar.gz" -C "$UPDATE_DIR" .
|
||||||
find "/opt/so/repo" -type f -not -name "$new_version.tar.gz" -exec rm -rf {} \;
|
find "/opt/so/repo" -type f -not -name "$new_version.tar.gz" -exec rm -rf {} \;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,136 +389,82 @@ masterunlock() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
preupgrade_changes_2.3.50_repo() {
|
|
||||||
# We made repo changes in 2.3.50 and this prepares for that on upgrade
|
|
||||||
echo "Checking to see if 2.3.50 repo changes are needed."
|
|
||||||
|
|
||||||
[[ "$INSTALLEDVERSION" == 2.3.30 || "$INSTALLEDVERSION" == 2.3.40 ]] && up_2.3.3X_to_2.3.50_repo
|
|
||||||
}
|
|
||||||
|
|
||||||
preupgrade_changes() {
|
preupgrade_changes() {
|
||||||
# This function is to add any new pillar items if needed.
|
# This function is to add any new pillar items if needed.
|
||||||
echo "Checking to see if changes are needed."
|
echo "Checking to see if changes are needed."
|
||||||
|
|
||||||
[[ "$INSTALLEDVERSION" =~ rc.1 ]] && rc1_to_rc2
|
[[ "$INSTALLEDVERSION" == 2.3.0 || "$INSTALLEDVERSION" == 2.3.1 || "$INSTALLEDVERSION" == 2.3.2 || "$INSTALLEDVERSION" == 2.3.10 ]] && up_to_2.3.20
|
||||||
[[ "$INSTALLEDVERSION" =~ rc.2 ]] && rc2_to_rc3
|
[[ "$INSTALLEDVERSION" == 2.3.20 || "$INSTALLEDVERSION" == 2.3.21 ]] && up_to_2.3.30
|
||||||
[[ "$INSTALLEDVERSION" =~ rc.3 ]] && rc3_to_2.3.0
|
[[ "$INSTALLEDVERSION" == 2.3.30 || "$INSTALLEDVERSION" == 2.3.40 ]] && up_to_2.3.50
|
||||||
[[ "$INSTALLEDVERSION" == 2.3.0 || "$INSTALLEDVERSION" == 2.3.1 || "$INSTALLEDVERSION" == 2.3.2 || "$INSTALLEDVERSION" == 2.3.10 ]] && up_2.3.0_to_2.3.20
|
[[ "$INSTALLEDVERSION" == 2.3.50 || "$INSTALLEDVERSION" == 2.3.51 || "$INSTALLEDVERSION" == 2.3.52 || "$INSTALLEDVERSION" == 2.3.60 || "$INSTALLEDVERSION" == 2.3.61 || "$INSTALLEDVERSION" == 2.3.70 ]] && up_to_2.3.80
|
||||||
[[ "$INSTALLEDVERSION" == 2.3.20 || "$INSTALLEDVERSION" == 2.3.21 ]] && up_2.3.2X_to_2.3.30
|
[[ "$INSTALLEDVERSION" == 2.3.80 ]] && up_to_2.3.90
|
||||||
[[ "$INSTALLEDVERSION" == 2.3.30 || "$INSTALLEDVERSION" == 2.3.40 ]] && up_2.3.3X_to_2.3.50
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
postupgrade_changes() {
|
postupgrade_changes() {
|
||||||
# This function is to add any new pillar items if needed.
|
# This function is to add any new pillar items if needed.
|
||||||
echo "Running post upgrade processes."
|
echo "Running post upgrade processes."
|
||||||
|
|
||||||
[[ "$POSTVERSION" =~ rc.1 ]] && post_rc1_to_rc2
|
[[ "$POSTVERSION" == 2.3.0 || "$POSTVERSION" == 2.3.1 || "$POSTVERSION" == 2.3.2 || "$POSTVERSION" == 2.3.10 || "$POSTVERSION" == 2.3.20 ]] && post_to_2.3.21
|
||||||
[[ "$POSTVERSION" == 2.3.20 || "$POSTVERSION" == 2.3.21 ]] && post_2.3.2X_to_2.3.30
|
[[ "$POSTVERSION" == 2.3.21 || "$POSTVERSION" == 2.3.30 ]] && post_to_2.3.40
|
||||||
[[ "$POSTVERSION" == 2.3.30 ]] && post_2.3.30_to_2.3.40
|
[[ "$POSTVERSION" == 2.3.40 || "$POSTVERSION" == 2.3.50 || "$POSTVERSION" == 2.3.51 || "$POSTVERSION" == 2.3.52 ]] && post_to_2.3.60
|
||||||
|
[[ "$POSTVERSION" == 2.3.60 || "$POSTVERSION" == 2.3.61 || "$POSTVERSION" == 2.3.70 || "$POSTVERSION" == 2.3.80 ]] && post_to_2.3.90
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
post_rc1_to_2.3.21() {
|
post_to_2.3.21() {
|
||||||
salt-call state.apply playbook.OLD_db_init
|
salt-call state.apply playbook.OLD_db_init
|
||||||
rm -f /opt/so/rules/elastalert/playbook/*.yaml
|
rm -f /opt/so/rules/elastalert/playbook/*.yaml
|
||||||
so-playbook-ruleupdate >> /root/soup_playbook_rule_update.log 2>&1 &
|
so-playbook-ruleupdate >> /root/soup_playbook_rule_update.log 2>&1 &
|
||||||
POSTVERSION=2.3.21
|
POSTVERSION=2.3.21
|
||||||
}
|
}
|
||||||
|
|
||||||
post_2.3.2X_to_2.3.30() {
|
post_to_2.3.40() {
|
||||||
so-playbook-sigma-refresh >> /root/soup_playbook_sigma_refresh.log 2>&1 &
|
|
||||||
POSTVERSION=2.3.30
|
|
||||||
}
|
|
||||||
|
|
||||||
post_2.3.30_to_2.3.40() {
|
|
||||||
so-playbook-sigma-refresh >> /root/soup_playbook_sigma_refresh.log 2>&1 &
|
so-playbook-sigma-refresh >> /root/soup_playbook_sigma_refresh.log 2>&1 &
|
||||||
so-kibana-space-defaults
|
so-kibana-space-defaults
|
||||||
POSTVERSION=2.3.40
|
POSTVERSION=2.3.40
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post_to_2.3.60() {
|
||||||
|
for table in identity_recovery_addresses selfservice_recovery_flows selfservice_registration_flows selfservice_verification_flows identities identity_verification_tokens identity_credentials selfservice_settings_flows identity_recovery_tokens continuity_containers identity_credential_identifiers identity_verifiable_addresses courier_messages selfservice_errors sessions selfservice_login_flows
|
||||||
|
do
|
||||||
|
echo "Forcing Kratos network migration: $table"
|
||||||
|
sqlite3 /opt/so/conf/kratos/db/db.sqlite "update $table set nid=(select id from networks limit 1);"
|
||||||
|
done
|
||||||
|
|
||||||
rc1_to_rc2() {
|
POSTVERSION=2.3.60
|
||||||
|
|
||||||
# Move the static file to global.sls
|
|
||||||
echo "Migrating static.sls to global.sls"
|
|
||||||
mv -v /opt/so/saltstack/local/pillar/static.sls /opt/so/saltstack/local/pillar/global.sls >> "$SOUP_LOG" 2>&1
|
|
||||||
sed -i '1c\global:' /opt/so/saltstack/local/pillar/global.sls >> "$SOUP_LOG" 2>&1
|
|
||||||
|
|
||||||
# Moving baseurl from minion sls file to inside global.sls
|
|
||||||
local line=$(grep '^ url_base:' /opt/so/saltstack/local/pillar/minions/$MINIONID.sls)
|
|
||||||
sed -i '/^ url_base:/d' /opt/so/saltstack/local/pillar/minions/$MINIONID.sls;
|
|
||||||
sed -i "/^global:/a \\$line" /opt/so/saltstack/local/pillar/global.sls;
|
|
||||||
|
|
||||||
# Adding play values to the global.sls
|
|
||||||
local HIVEPLAYSECRET=$(get_random_value)
|
|
||||||
local CORTEXPLAYSECRET=$(get_random_value)
|
|
||||||
sed -i "/^global:/a \\ hiveplaysecret: $HIVEPLAYSECRET" /opt/so/saltstack/local/pillar/global.sls;
|
|
||||||
sed -i "/^global:/a \\ cortexplaysecret: $CORTEXPLAYSECRET" /opt/so/saltstack/local/pillar/global.sls;
|
|
||||||
|
|
||||||
# Move storage nodes to hostname for SSL
|
|
||||||
# Get a list we can use:
|
|
||||||
grep -A1 searchnode /opt/so/saltstack/local/pillar/data/nodestab.sls | grep -v '\-\-' | sed '$!N;s/\n/ /' | awk '{print $1,$3}' | awk '/_searchnode:/{gsub(/\_searchnode:/, "_searchnode"); print}' >/tmp/nodes.txt
|
|
||||||
# Remove the nodes from cluster settings
|
|
||||||
while read p; do
|
|
||||||
local NAME=$(echo $p | awk '{print $1}')
|
|
||||||
local IP=$(echo $p | awk '{print $2}')
|
|
||||||
echo "Removing the old cross cluster config for $NAME"
|
|
||||||
curl -XPUT -H 'Content-Type: application/json' http://localhost:9200/_cluster/settings -d '{"persistent":{"cluster":{"remote":{"'$NAME'":{"skip_unavailable":null,"seeds":null}}}}}'
|
|
||||||
done </tmp/nodes.txt
|
|
||||||
# Add the nodes back using hostname
|
|
||||||
while read p; do
|
|
||||||
local NAME=$(echo $p | awk '{print $1}')
|
|
||||||
local EHOSTNAME=$(echo $p | awk -F"_" '{print $1}')
|
|
||||||
local IP=$(echo $p | awk '{print $2}')
|
|
||||||
echo "Adding the new cross cluster config for $NAME"
|
|
||||||
curl -XPUT http://localhost:9200/_cluster/settings -H'Content-Type: application/json' -d '{"persistent": {"search": {"remote": {"'$NAME'": {"skip_unavailable": "true", "seeds": ["'$EHOSTNAME':9300"]}}}}}'
|
|
||||||
done </tmp/nodes.txt
|
|
||||||
|
|
||||||
INSTALLEDVERSION=rc.2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc2_to_rc3() {
|
post_to_2.3.90() {
|
||||||
|
# Do Kibana dashboard things
|
||||||
|
salt-call state.apply kibana.so_savedobjects_defaults queue=True
|
||||||
|
|
||||||
# move location of local.rules
|
# Create FleetDM service account
|
||||||
cp /opt/so/saltstack/default/salt/idstools/localrules/local.rules /opt/so/saltstack/local/salt/idstools/local.rules
|
FLEET_MANAGER=$(lookup_pillar fleet_manager)
|
||||||
|
if [[ "$FLEET_MANAGER" == "True" ]]; then
|
||||||
|
FLEET_SA_EMAIL=$(lookup_pillar_secret fleet_sa_email)
|
||||||
|
FLEET_SA_PW=$(lookup_pillar_secret fleet_sa_password)
|
||||||
|
MYSQL_PW=$(lookup_pillar_secret mysql)
|
||||||
|
|
||||||
if [ -f /opt/so/saltstack/local/salt/idstools/localrules/local.rules ]; then
|
FLEET_HASH=$(docker exec so-soctopus python -c "import bcrypt; print(bcrypt.hashpw('$FLEET_SA_PW'.encode('utf-8'), bcrypt.gensalt()).decode('utf-8'));" 2>&1)
|
||||||
cat /opt/so/saltstack/local/salt/idstools/localrules/local.rules >> /opt/so/saltstack/local/salt/idstools/local.rules
|
MYSQL_OUTPUT=$(docker exec so-mysql mysql -u root --password=$MYSQL_PW fleet -e \
|
||||||
|
"INSERT INTO users (password,salt,email,name,global_role) VALUES ('$FLEET_HASH','','$FLEET_SA_EMAIL','$FLEET_SA_EMAIL','admin')" 2>&1)
|
||||||
|
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo "Successfully added service account to Fleet"
|
||||||
|
else
|
||||||
|
echo "Unable to add service account to Fleet"
|
||||||
|
echo "$MYSQL_OUTPUT"
|
||||||
fi
|
fi
|
||||||
rm -rf /opt/so/saltstack/local/salt/idstools/localrules
|
|
||||||
rm -rf /opt/so/saltstack/default/salt/idstools/localrules
|
|
||||||
|
|
||||||
# Rename mdengine to MDENGINE
|
|
||||||
sed -i "s/ zeekversion/ mdengine/g" /opt/so/saltstack/local/pillar/global.sls
|
|
||||||
# Enable Strelka Rules
|
|
||||||
sed -i "/ rules:/c\ rules: 1" /opt/so/saltstack/local/pillar/global.sls
|
|
||||||
|
|
||||||
INSTALLEDVERSION=rc.3
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
rc3_to_2.3.0() {
|
|
||||||
# Fix Tab Complete
|
|
||||||
if [ ! -f /etc/profile.d/securityonion.sh ]; then
|
|
||||||
echo "complete -cf sudo" > /etc/profile.d/securityonion.sh
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{
|
|
||||||
echo "redis_settings:"
|
|
||||||
echo " redis_maxmemory: 827"
|
|
||||||
echo "playbook:"
|
|
||||||
echo " api_key: de6639318502476f2fa5aa06f43f51fb389a3d7f"
|
|
||||||
} >> /opt/so/saltstack/local/pillar/global.sls
|
|
||||||
|
|
||||||
sed -i 's/playbook:/playbook_db:/' /opt/so/saltstack/local/pillar/secrets.sls
|
|
||||||
{
|
|
||||||
echo "playbook_admin: $(get_random_value)"
|
|
||||||
echo "playbook_automation: $(get_random_value)"
|
|
||||||
} >> /opt/so/saltstack/local/pillar/secrets.sls
|
|
||||||
|
|
||||||
INSTALLEDVERSION=2.3.0
|
POSTVERSION=2.3.90
|
||||||
}
|
}
|
||||||
|
|
||||||
up_2.3.0_to_2.3.20(){
|
|
||||||
|
up_to_2.3.20(){
|
||||||
DOCKERSTUFFBIP=$(echo $DOCKERSTUFF | awk -F'.' '{print $1,$2,$3,1}' OFS='.')/24
|
DOCKERSTUFFBIP=$(echo $DOCKERSTUFF | awk -F'.' '{print $1,$2,$3,1}' OFS='.')/24
|
||||||
# Remove PCAP from global
|
# Remove PCAP from global
|
||||||
sed '/pcap:/d' /opt/so/saltstack/local/pillar/global.sls
|
sed '/pcap:/d' /opt/so/saltstack/local/pillar/global.sls
|
||||||
@@ -414,7 +502,7 @@ up_2.3.0_to_2.3.20(){
|
|||||||
INSTALLEDVERSION=2.3.20
|
INSTALLEDVERSION=2.3.20
|
||||||
}
|
}
|
||||||
|
|
||||||
up_2.3.2X_to_2.3.30() {
|
up_to_2.3.30() {
|
||||||
# Replace any curly brace scalars with the same scalar in single quotes
|
# Replace any curly brace scalars with the same scalar in single quotes
|
||||||
readarray -t minion_pillars <<< "$(find /opt/so/saltstack/local/pillar/minions -type f -name '*.sls')"
|
readarray -t minion_pillars <<< "$(find /opt/so/saltstack/local/pillar/minions -type f -name '*.sls')"
|
||||||
for pillar in "${minion_pillars[@]}"; do
|
for pillar in "${minion_pillars[@]}"; do
|
||||||
@@ -426,7 +514,7 @@ up_2.3.2X_to_2.3.30() {
|
|||||||
sed -i "/ imagerepo: securityonion/c\ imagerepo: 'security-onion-solutions'" /opt/so/saltstack/local/pillar/global.sls
|
sed -i "/ imagerepo: securityonion/c\ imagerepo: 'security-onion-solutions'" /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
|
||||||
# Strelka rule repo pillar addition
|
# Strelka rule repo pillar addition
|
||||||
if [ $is_airgap -eq 0 ]; then
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
# Add manager as default Strelka YARA rule repo
|
# Add manager as default Strelka YARA rule repo
|
||||||
sed -i "/^strelka:/a \\ repos: \n - https://$HOSTNAME/repo/rules/strelka" /opt/so/saltstack/local/pillar/global.sls;
|
sed -i "/^strelka:/a \\ repos: \n - https://$HOSTNAME/repo/rules/strelka" /opt/so/saltstack/local/pillar/global.sls;
|
||||||
else
|
else
|
||||||
@@ -437,32 +525,7 @@ up_2.3.2X_to_2.3.30() {
|
|||||||
INSTALLEDVERSION=2.3.30
|
INSTALLEDVERSION=2.3.30
|
||||||
}
|
}
|
||||||
|
|
||||||
up_2.3.3X_to_2.3.50_repo() {
|
up_to_2.3.50() {
|
||||||
echo "Performing 2.3.50 repo actions."
|
|
||||||
if [[ "$OS" == "centos" ]]; then
|
|
||||||
# Import GPG Keys
|
|
||||||
gpg_rpm_import
|
|
||||||
echo "Disabling fastestmirror."
|
|
||||||
disable_fastestmirror
|
|
||||||
echo "Deleting unneeded repo files."
|
|
||||||
DELREPOS=('CentOS-Base' 'CentOS-CR' 'CentOS-Debuginfo' 'docker-ce' 'CentOS-fasttrack' 'CentOS-Media' 'CentOS-Sources' 'CentOS-Vault' 'CentOS-x86_64-kernel' 'epel' 'epel-testing' 'saltstack' 'wazuh')
|
|
||||||
|
|
||||||
for DELREPO in "${DELREPOS[@]}"; do
|
|
||||||
if [[ -f "/etc/yum.repos.d/$DELREPO.repo" ]]; then
|
|
||||||
echo "Deleting $DELREPO.repo"
|
|
||||||
rm -f "/etc/yum.repos.d/$DELREPO.repo"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ $is_airgap -eq 1 ]; then
|
|
||||||
# Copy the new repo file if not airgap
|
|
||||||
cp $UPDATE_DIR/salt/repo/client/files/centos/securityonion.repo /etc/yum.repos.d/
|
|
||||||
yum clean all
|
|
||||||
yum repolist
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
up_2.3.3X_to_2.3.50() {
|
|
||||||
|
|
||||||
cat <<EOF > /tmp/supersed.txt
|
cat <<EOF > /tmp/supersed.txt
|
||||||
/so-zeek:/ {
|
/so-zeek:/ {
|
||||||
@@ -494,6 +557,89 @@ EOF
|
|||||||
INSTALLEDVERSION=2.3.50
|
INSTALLEDVERSION=2.3.50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up_to_2.3.80() {
|
||||||
|
|
||||||
|
# Remove watermark settings from global.sls
|
||||||
|
sed -i '/ cluster_routing_allocation_disk/d' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
|
||||||
|
# Add new indices to the global
|
||||||
|
sed -i '/ index_settings:/a \\ so-elasticsearch: \n shards: 1 \n warm: 7 \n close: 30 \n delete: 365' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
sed -i '/ index_settings:/a \\ so-logstash: \n shards: 1 \n warm: 7 \n close: 30 \n delete: 365' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
sed -i '/ index_settings:/a \\ so-kibana: \n shards: 1 \n warm: 7 \n close: 30 \n delete: 365' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
sed -i '/ index_settings:/a \\ so-redis: \n shards: 1 \n warm: 7 \n close: 30 \n delete: 365' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
|
||||||
|
# Do some pillar formatting
|
||||||
|
tc=$(grep -w true_cluster /opt/so/saltstack/local/pillar/global.sls | awk -F: {'print tolower($2)'}| xargs)
|
||||||
|
|
||||||
|
if [[ "$tc" == "true" ]]; then
|
||||||
|
tcname=$(grep -w true_cluster_name /opt/so/saltstack/local/pillar/global.sls | awk -F: {'print $2'})
|
||||||
|
sed -i "/^elasticsearch:/a \\ config: \n cluster: \n name: $tcname" /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
sed -i '/ true_cluster_name/d' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
sed -i '/ esclustername/d' /opt/so/saltstack/local/pillar/global.sls
|
||||||
|
|
||||||
|
for file in /opt/so/saltstack/local/pillar/minions/*.sls; do
|
||||||
|
if [[ ${file} != *"manager.sls"* ]]; then
|
||||||
|
noderoutetype=$(grep -w node_route_type $file | awk -F: {'print $2'})
|
||||||
|
if [ -n "$noderoutetype" ]; then
|
||||||
|
sed -i "/^elasticsearch:/a \\ config: \n node: \n attr: \n box_type: $noderoutetype" $file
|
||||||
|
sed -i '/ node_route_type/d' $file
|
||||||
|
noderoutetype=''
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for local es config to inform user that the config in local is now ignored and those options need to be placed in the pillar
|
||||||
|
if [ -f "/opt/so/saltstack/local/salt/elasticsearch/files/elasticsearch.yml" ]; then
|
||||||
|
NOTIFYCUSTOMELASTICCONFIG=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
INSTALLEDVERSION=2.3.80
|
||||||
|
}
|
||||||
|
|
||||||
|
up_to_2.3.90() {
|
||||||
|
for i in manager managersearch eval standalone; do
|
||||||
|
if compgen -G "/opt/so/saltstack/local/pillar/minions/*_$i.sls" > /dev/null; then
|
||||||
|
echo "soc:" >> /opt/so/saltstack/local/pillar/minions/*_$i.sls
|
||||||
|
sed -i "/^soc:/a \\ es_index_patterns: '*:so-*,*:endgame-*'" /opt/so/saltstack/local/pillar/minions/*_$i.sls
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create Endgame Hostgroup
|
||||||
|
so-firewall addhostgroup endgame
|
||||||
|
|
||||||
|
# Force influx to generate a new cert
|
||||||
|
mv /etc/pki/influxdb.crt /etc/pki/influxdb.crt.2390upgrade
|
||||||
|
mv /etc/pki/influxdb.key /etc/pki/influxdb.key.2390upgrade
|
||||||
|
|
||||||
|
# remove old common ingest pipeline in default
|
||||||
|
rm -vf /opt/so/saltstack/default/salt/elasticsearch/files/ingest/common
|
||||||
|
# if custom common, move from local ingest to local ingest-dynamic
|
||||||
|
mkdir -vp /opt/so/saltstack/local/salt/elasticsearch/files/ingest-dynamic
|
||||||
|
if [[ -f "/opt/so/saltstack/local/salt/elasticsearch/files/ingest/common" ]]; then
|
||||||
|
mv -v /opt/so/saltstack/local/salt/elasticsearch/files/ingest/common /opt/so/saltstack/local/salt/elasticsearch/files/ingest-dynamic/common
|
||||||
|
# since json file, we need to wrap with raw
|
||||||
|
sed -i '1s/^/{{'{% raw %}'}}\n/' /opt/so/saltstack/local/salt/elasticsearch/files/ingest-dynamic/common
|
||||||
|
sed -i -e '$a{{'{% endraw %}'}}\n' /opt/so/saltstack/local/salt/elasticsearch/files/ingest-dynamic/common
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate FleetDM Service Account creds if they do not exist
|
||||||
|
if grep -q "fleet_sa_email" /opt/so/saltstack/local/pillar/secrets.sls; then
|
||||||
|
echo "FleetDM Service Account credentials already created..."
|
||||||
|
else
|
||||||
|
echo "Generating FleetDM Service Account credentials..."
|
||||||
|
FLEETSAPASS=$(get_random_value)
|
||||||
|
printf '%s\n'\
|
||||||
|
" fleet_sa_email: service.account@securityonion.invalid"\
|
||||||
|
" fleet_sa_password: $FLEETSAPASS"\
|
||||||
|
>> /opt/so/saltstack/local/pillar/secrets.sls
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
INSTALLEDVERSION=2.3.90
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
verify_upgradespace() {
|
verify_upgradespace() {
|
||||||
CURRENTSPACE=$(df -BG / | grep -v Avail | awk '{print $4}' | sed 's/.$//')
|
CURRENTSPACE=$(df -BG / | grep -v Avail | awk '{print $4}' | sed 's/.$//')
|
||||||
if [ "$CURRENTSPACE" -lt "10" ]; then
|
if [ "$CURRENTSPACE" -lt "10" ]; then
|
||||||
@@ -509,7 +655,7 @@ upgrade_space() {
|
|||||||
clean_dockers
|
clean_dockers
|
||||||
if ! verify_upgradespace; then
|
if ! verify_upgradespace; then
|
||||||
echo "There is not enough space to perform the upgrade. Please free up space and try again"
|
echo "There is not enough space to perform the upgrade. Please free up space and try again"
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "You have enough space for upgrade. Proceeding with soup."
|
echo "You have enough space for upgrade. Proceeding with soup."
|
||||||
@@ -534,8 +680,8 @@ thehive_maint() {
|
|||||||
done
|
done
|
||||||
if [ "$THEHIVE_CONNECTED" == "yes" ]; then
|
if [ "$THEHIVE_CONNECTED" == "yes" ]; then
|
||||||
echo "Migrating thehive databases if needed."
|
echo "Migrating thehive databases if needed."
|
||||||
curl -v -k -XPOST -L "https://localhost/thehive/api/maintenance/migrate"
|
curl -v -k -XPOST -L "https://localhost/thehive/api/maintenance/migrate" >> "$SOUP_LOG" 2>&1
|
||||||
curl -v -k -XPOST -L "https://localhost/cortex/api/maintenance/migrate"
|
curl -v -k -XPOST -L "https://localhost/cortex/api/maintenance/migrate" >> "$SOUP_LOG" 2>&1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +715,7 @@ upgrade_check() {
|
|||||||
# Let's make sure we actually need to update.
|
# Let's make sure we actually need to update.
|
||||||
NEWVERSION=$(cat $UPDATE_DIR/VERSION)
|
NEWVERSION=$(cat $UPDATE_DIR/VERSION)
|
||||||
HOTFIXVERSION=$(cat $UPDATE_DIR/HOTFIX)
|
HOTFIXVERSION=$(cat $UPDATE_DIR/HOTFIX)
|
||||||
CURRENTHOTFIX=$(cat /etc/sohotfix 2>/dev/null)
|
[[ -f /etc/sohotfix ]] && CURRENTHOTFIX=$(cat /etc/sohotfix)
|
||||||
if [ "$INSTALLEDVERSION" == "$NEWVERSION" ]; then
|
if [ "$INSTALLEDVERSION" == "$NEWVERSION" ]; then
|
||||||
echo "Checking to see if there are hotfixes needed"
|
echo "Checking to see if there are hotfixes needed"
|
||||||
if [ "$HOTFIXVERSION" == "$CURRENTHOTFIX" ]; then
|
if [ "$HOTFIXVERSION" == "$CURRENTHOTFIX" ]; then
|
||||||
@@ -586,13 +732,14 @@ upgrade_check() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
upgrade_check_salt() {
|
upgrade_check_salt() {
|
||||||
NEWSALTVERSION=$(grep version: $UPDATE_DIR/salt/salt/master.defaults.yaml | awk {'print $2'})
|
NEWSALTVERSION=$(grep version: $UPDATE_DIR/salt/salt/master.defaults.yaml | awk '{print $2}')
|
||||||
if [ "$INSTALLEDSALTVERSION" == "$NEWSALTVERSION" ]; then
|
if [ "$INSTALLEDSALTVERSION" == "$NEWSALTVERSION" ]; then
|
||||||
echo "You are already running the correct version of Salt for Security Onion."
|
echo "You are already running the correct version of Salt for Security Onion."
|
||||||
else
|
else
|
||||||
UPGRADESALT=1
|
UPGRADESALT=1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
upgrade_salt() {
|
upgrade_salt() {
|
||||||
SALTUPGRADED=True
|
SALTUPGRADED=True
|
||||||
echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION."
|
echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION."
|
||||||
@@ -604,7 +751,11 @@ upgrade_salt() {
|
|||||||
yum versionlock delete "salt-*"
|
yum versionlock delete "salt-*"
|
||||||
echo "Updating Salt packages and restarting services."
|
echo "Updating Salt packages and restarting services."
|
||||||
echo ""
|
echo ""
|
||||||
sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -r -F -M -x python3 stable "$NEWSALTVERSION"
|
set +e
|
||||||
|
run_check_net_err \
|
||||||
|
"sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -r -F -M -x python3 stable \"$NEWSALTVERSION\"" \
|
||||||
|
"Could not update salt, please check $SOUP_LOG for details."
|
||||||
|
set -e
|
||||||
echo "Applying yum versionlock for Salt."
|
echo "Applying yum versionlock for Salt."
|
||||||
echo ""
|
echo ""
|
||||||
yum versionlock add "salt-*"
|
yum versionlock add "salt-*"
|
||||||
@@ -617,7 +768,11 @@ upgrade_salt() {
|
|||||||
apt-mark unhold "salt-minion"
|
apt-mark unhold "salt-minion"
|
||||||
echo "Updating Salt packages and restarting services."
|
echo "Updating Salt packages and restarting services."
|
||||||
echo ""
|
echo ""
|
||||||
sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -F -M -x python3 stable "$NEWSALTVERSION"
|
set +e
|
||||||
|
run_check_net_err \
|
||||||
|
"sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -F -M -x python3 stable \"$NEWSALTVERSION\"" \
|
||||||
|
"Could not update salt, please check $SOUP_LOG for details."
|
||||||
|
set -e
|
||||||
echo "Applying apt hold for Salt."
|
echo "Applying apt hold for Salt."
|
||||||
echo ""
|
echo ""
|
||||||
apt-mark hold "salt-common"
|
apt-mark hold "salt-common"
|
||||||
@@ -626,6 +781,31 @@ upgrade_salt() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upgrade_to_2.3.50_repo() {
|
||||||
|
echo "Performing repo changes."
|
||||||
|
if [[ "$OS" == "centos" ]]; then
|
||||||
|
# Import GPG Keys
|
||||||
|
gpg_rpm_import
|
||||||
|
echo "Disabling fastestmirror."
|
||||||
|
disable_fastestmirror
|
||||||
|
echo "Deleting unneeded repo files."
|
||||||
|
DELREPOS=('CentOS-Base' 'CentOS-CR' 'CentOS-Debuginfo' 'docker-ce' 'CentOS-fasttrack' 'CentOS-Media' 'CentOS-Sources' 'CentOS-Vault' 'CentOS-x86_64-kernel' 'epel' 'epel-testing' 'saltstack' 'wazuh')
|
||||||
|
|
||||||
|
for DELREPO in "${DELREPOS[@]}"; do
|
||||||
|
if [[ -f "/etc/yum.repos.d/$DELREPO.repo" ]]; then
|
||||||
|
echo "Deleting $DELREPO.repo"
|
||||||
|
rm -f "/etc/yum.repos.d/$DELREPO.repo"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $is_airgap -eq 1 ]]; then
|
||||||
|
# Copy the new repo file if not airgap
|
||||||
|
cp $UPDATE_DIR/salt/repo/client/files/centos/securityonion.repo /etc/yum.repos.d/
|
||||||
|
yum clean all
|
||||||
|
yum repolist
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
verify_latest_update_script() {
|
verify_latest_update_script() {
|
||||||
# Check to see if the update scripts match. If not run the new one.
|
# Check to see if the update scripts match. If not run the new one.
|
||||||
CURRENTSOUP=$(md5sum /opt/so/saltstack/default/salt/common/tools/sbin/soup | awk '{print $1}')
|
CURRENTSOUP=$(md5sum /opt/so/saltstack/default/salt/common/tools/sbin/soup | awk '{print $1}')
|
||||||
@@ -642,7 +822,7 @@ verify_latest_update_script() {
|
|||||||
cp $UPDATE_DIR/salt/common/tools/sbin/soup $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
cp $UPDATE_DIR/salt/common/tools/sbin/soup $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
||||||
cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
||||||
cp $UPDATE_DIR/salt/common/tools/sbin/so-image-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
cp $UPDATE_DIR/salt/common/tools/sbin/so-image-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/
|
||||||
salt-call state.apply common queue=True
|
salt-call state.apply -l info common queue=True
|
||||||
echo ""
|
echo ""
|
||||||
echo "soup has been updated. Please run soup again."
|
echo "soup has been updated. Please run soup again."
|
||||||
exit 0
|
exit 0
|
||||||
@@ -650,50 +830,41 @@ verify_latest_update_script() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
echo "### Preparing soup at `date` ###"
|
trap 'check_err $?' EXIT
|
||||||
while getopts ":b" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
b ) # process option b
|
|
||||||
shift
|
|
||||||
BATCHSIZE=$1
|
|
||||||
if ! [[ "$BATCHSIZE" =~ ^[0-9]+$ ]]; then
|
|
||||||
echo "Batch size must be a number greater than 0."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
\? )
|
|
||||||
echo "Usage: cmd [-b]"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
|
check_pillar_items
|
||||||
|
|
||||||
|
echo "Checking to see if this is an airgap install."
|
||||||
|
echo ""
|
||||||
|
check_airgap
|
||||||
|
if [[ $is_airgap -eq 0 && $UNATTENDED == true && -z $ISOLOC ]]; then
|
||||||
|
echo "Missing file argument (-f <FILENAME>) for unattended airgap upgrade."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
echo "Checking to see if this is a manager."
|
echo "Checking to see if this is a manager."
|
||||||
echo ""
|
echo ""
|
||||||
require_manager
|
require_manager
|
||||||
set_minionid
|
set_minionid
|
||||||
echo "Checking to see if this is an airgap install"
|
|
||||||
echo ""
|
|
||||||
check_airgap
|
|
||||||
echo "Found that Security Onion $INSTALLEDVERSION is currently installed."
|
echo "Found that Security Onion $INSTALLEDVERSION is currently installed."
|
||||||
echo ""
|
echo ""
|
||||||
set_os
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
set_palette
|
|
||||||
check_elastic_license
|
|
||||||
echo ""
|
|
||||||
if [ $is_airgap -eq 0 ]; then
|
|
||||||
# Let's mount the ISO since this is airgap
|
# Let's mount the ISO since this is airgap
|
||||||
airgap_mounted
|
airgap_mounted
|
||||||
else
|
else
|
||||||
echo "Cloning Security Onion github repo into $UPDATE_DIR."
|
echo "Cloning Security Onion github repo into $UPDATE_DIR."
|
||||||
echo "Removing previous upgrade sources."
|
echo "Removing previous upgrade sources."
|
||||||
rm -rf $UPDATE_DIR
|
rm -rf $UPDATE_DIR
|
||||||
|
echo "Cloning the Security Onion Repo."
|
||||||
clone_to_tmp
|
clone_to_tmp
|
||||||
fi
|
fi
|
||||||
check_os_updates
|
|
||||||
echo ""
|
|
||||||
echo "Verifying we have the latest soup script."
|
echo "Verifying we have the latest soup script."
|
||||||
verify_latest_update_script
|
verify_latest_update_script
|
||||||
echo ""
|
echo ""
|
||||||
|
set_os
|
||||||
|
set_palette
|
||||||
|
check_elastic_license
|
||||||
|
echo ""
|
||||||
|
check_os_updates
|
||||||
|
|
||||||
echo "Generating new repo archive"
|
echo "Generating new repo archive"
|
||||||
generate_and_clean_tarballs
|
generate_and_clean_tarballs
|
||||||
@@ -709,7 +880,7 @@ upgrade_space
|
|||||||
|
|
||||||
echo "Checking for Salt Master and Minion updates."
|
echo "Checking for Salt Master and Minion updates."
|
||||||
upgrade_check_salt
|
upgrade_check_salt
|
||||||
|
set -e
|
||||||
|
|
||||||
if [ "$is_hotfix" == "true" ]; then
|
if [ "$is_hotfix" == "true" ]; then
|
||||||
echo "Applying $HOTFIXVERSION"
|
echo "Applying $HOTFIXVERSION"
|
||||||
@@ -717,37 +888,40 @@ if [ "$is_hotfix" == "true" ]; then
|
|||||||
echo ""
|
echo ""
|
||||||
update_version
|
update_version
|
||||||
salt-call state.highstate -l info queue=True
|
salt-call state.highstate -l info queue=True
|
||||||
|
|
||||||
else
|
else
|
||||||
echo ""
|
echo ""
|
||||||
echo "Performing upgrade from Security Onion $INSTALLEDVERSION to Security Onion $NEWVERSION."
|
echo "Performing upgrade from Security Onion $INSTALLEDVERSION to Security Onion $NEWVERSION."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "Updating dockers to $NEWVERSION."
|
echo "Updating dockers to $NEWVERSION."
|
||||||
if [ $is_airgap -eq 0 ]; then
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
airgap_update_dockers
|
airgap_update_dockers
|
||||||
update_centos_repo
|
update_centos_repo
|
||||||
yum clean all
|
yum clean all
|
||||||
check_os_updates
|
check_os_updates
|
||||||
else
|
else
|
||||||
update_registry
|
update_registry
|
||||||
|
set +e
|
||||||
update_docker_containers "soup"
|
update_docker_containers "soup"
|
||||||
|
set -e
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Stopping Salt Minion service."
|
echo "Stopping Salt Minion service."
|
||||||
systemctl stop salt-minion
|
systemctl stop salt-minion
|
||||||
echo "Killing any remaining Salt Minion processes."
|
echo "Killing any remaining Salt Minion processes."
|
||||||
|
set +e
|
||||||
pkill -9 -ef /usr/bin/salt-minion
|
pkill -9 -ef /usr/bin/salt-minion
|
||||||
|
set -e
|
||||||
echo ""
|
echo ""
|
||||||
echo "Stopping Salt Master service."
|
echo "Stopping Salt Master service."
|
||||||
systemctl stop salt-master
|
systemctl stop salt-master
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
preupgrade_changes_2.3.50_repo
|
upgrade_to_2.3.50_repo
|
||||||
|
|
||||||
# Does salt need upgraded. If so update it.
|
# Does salt need upgraded. If so update it.
|
||||||
if [ "$UPGRADESALT" == "1" ]; then
|
if [[ $UPGRADESALT -eq 1 ]]; then
|
||||||
echo "Upgrading Salt"
|
echo "Upgrading Salt"
|
||||||
# Update the repo files so it can actually upgrade
|
# Update the repo files so it can actually upgrade
|
||||||
upgrade_salt
|
upgrade_salt
|
||||||
@@ -756,13 +930,13 @@ else
|
|||||||
echo "Checking if Salt was upgraded."
|
echo "Checking if Salt was upgraded."
|
||||||
echo ""
|
echo ""
|
||||||
# Check that Salt was upgraded
|
# Check that Salt was upgraded
|
||||||
SALTVERSIONPOSTUPGRADE=$(salt --versions-report | grep Salt: | awk {'print $2'})
|
SALTVERSIONPOSTUPGRADE=$(salt --versions-report | grep Salt: | awk '{print $2}')
|
||||||
if [[ "$SALTVERSIONPOSTUPGRADE" != "$NEWSALTVERSION" ]]; then
|
if [[ "$SALTVERSIONPOSTUPGRADE" != "$NEWSALTVERSION" ]]; then
|
||||||
echo "Salt upgrade failed. Check of indicators of failure in $SOUP_LOG."
|
echo "Salt upgrade failed. Check of indicators of failure in $SOUP_LOG."
|
||||||
echo "Once the issue is resolved, run soup again."
|
echo "Once the issue is resolved, run soup again."
|
||||||
echo "Exiting."
|
echo "Exiting."
|
||||||
echo ""
|
echo ""
|
||||||
exit 1
|
exit 0
|
||||||
else
|
else
|
||||||
echo "Salt upgrade success."
|
echo "Salt upgrade success."
|
||||||
echo ""
|
echo ""
|
||||||
@@ -771,13 +945,13 @@ else
|
|||||||
preupgrade_changes
|
preupgrade_changes
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [ $is_airgap -eq 0 ]; then
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
echo "Updating Rule Files to the Latest."
|
echo "Updating Rule Files to the Latest."
|
||||||
update_airgap_rules
|
update_airgap_rules
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Only update the repo if its airgap
|
# Only update the repo if its airgap
|
||||||
if [[ $is_airgap -eq 0 ]] && [[ "$UPGRADESALT" != "1" ]]; then
|
if [[ $is_airgap -eq 0 && $UPGRADESALT -ne 1 ]]; then
|
||||||
update_centos_repo
|
update_centos_repo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -795,6 +969,17 @@ else
|
|||||||
echo "Starting Salt Master service."
|
echo "Starting Salt Master service."
|
||||||
systemctl start salt-master
|
systemctl start salt-master
|
||||||
|
|
||||||
|
# Testing that salt-master is up by checking that is it connected to itself
|
||||||
|
set +e
|
||||||
|
echo "Waiting on the Salt Master service to be ready."
|
||||||
|
salt-call state.show_top -l error queue=True || fail "salt-master could not be reached. Check $SOUP_LOG for details."
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Ensuring python modules for Salt are installed and patched."
|
||||||
|
salt-call state.apply salt.python3-influxdb -l info queue=True
|
||||||
|
echo ""
|
||||||
|
|
||||||
# Only regenerate osquery packages if Fleet is enabled
|
# Only regenerate osquery packages if Fleet is enabled
|
||||||
FLEET_MANAGER=$(lookup_pillar fleet_manager)
|
FLEET_MANAGER=$(lookup_pillar fleet_manager)
|
||||||
FLEET_NODE=$(lookup_pillar fleet_node)
|
FLEET_NODE=$(lookup_pillar fleet_node)
|
||||||
@@ -807,9 +992,9 @@ else
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Running a highstate to complete the Security Onion upgrade on this manager. This could take several minutes."
|
echo "Running a highstate to complete the Security Onion upgrade on this manager. This could take several minutes."
|
||||||
|
set +e
|
||||||
salt-call state.highstate -l info queue=True
|
salt-call state.highstate -l info queue=True
|
||||||
echo ""
|
set -e
|
||||||
echo "Upgrade from $INSTALLEDVERSION to $NEWVERSION complete."
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Stopping Salt Master to remove ACL"
|
echo "Stopping Salt Master to remove ACL"
|
||||||
@@ -820,14 +1005,28 @@ else
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Starting Salt Master service."
|
echo "Starting Salt Master service."
|
||||||
systemctl start salt-master
|
systemctl start salt-master
|
||||||
|
|
||||||
|
set +e
|
||||||
|
echo "Waiting on the Salt Master service to be ready."
|
||||||
|
salt-call state.show_top -l error queue=True || fail "salt-master could not be reached. Check $SOUP_LOG for details."
|
||||||
|
set -e
|
||||||
|
|
||||||
echo "Running a highstate. This could take several minutes."
|
echo "Running a highstate. This could take several minutes."
|
||||||
salt-call state.highstate -l info queue=True
|
salt-call state.highstate -l info queue=True
|
||||||
postupgrade_changes
|
postupgrade_changes
|
||||||
unmount_update
|
[[ $is_airgap -eq 0 ]] && unmount_update
|
||||||
thehive_maint
|
thehive_maint
|
||||||
|
|
||||||
if [ "$UPGRADESALT" == "1" ]; then
|
echo ""
|
||||||
if [ $is_airgap -eq 0 ]; then
|
echo "Upgrade to $NEWVERSION complete."
|
||||||
|
|
||||||
|
# Everything beyond this is post-upgrade checking, don't fail past this point if something here causes an error
|
||||||
|
set +e
|
||||||
|
|
||||||
|
echo "Checking the number of minions."
|
||||||
|
NUM_MINIONS=$(ls /opt/so/saltstack/local/pillar/minions/*_*.sls | wc -l)
|
||||||
|
if [[ $UPGRADESALT -eq 1 ]] && [[ $NUM_MINIONS -gt 1 ]]; then
|
||||||
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "Cleaning repos on remote Security Onion nodes."
|
echo "Cleaning repos on remote Security Onion nodes."
|
||||||
salt -C 'not *_eval and not *_helixsensor and not *_manager and not *_managersearch and not *_standalone and G@os:CentOS' cmd.run "yum clean all"
|
salt -C 'not *_eval and not *_helixsensor and not *_manager and not *_managersearch and not *_standalone and G@os:CentOS' cmd.run "yum clean all"
|
||||||
@@ -835,8 +1034,15 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Checking for local modifications."
|
||||||
|
check_local_mods
|
||||||
|
|
||||||
|
echo "Checking sudoers file."
|
||||||
check_sudoers
|
check_sudoers
|
||||||
|
|
||||||
|
echo "Checking for necessary user migrations."
|
||||||
|
so-user migrate
|
||||||
|
|
||||||
if [[ -n $lsl_msg ]]; then
|
if [[ -n $lsl_msg ]]; then
|
||||||
case $lsl_msg in
|
case $lsl_msg in
|
||||||
'distributed')
|
'distributed')
|
||||||
@@ -853,9 +1059,7 @@ else
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NUM_MINIONS=$(ls /opt/so/saltstack/local/pillar/minions/*_*.sls | wc -l)
|
if [[ $NUM_MINIONS -gt 1 ]]; then
|
||||||
|
|
||||||
if [ $NUM_MINIONS -gt 1 ]; then
|
|
||||||
|
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
@@ -874,9 +1078,55 @@ EOF
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "### soup has been served at `date` ###"
|
if [ "$NOTIFYCUSTOMELASTICCONFIG" = true ] ; then
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
|
||||||
|
|
||||||
|
A custom Elasticsearch configuration has been found at /opt/so/saltstack/local/elasticsearch/files/elasticsearch.yml. This file is no longer referenced in Security Onion versions >= 2.3.80.
|
||||||
|
|
||||||
|
If you still need those customizations, you'll need to manually migrate them to the new Elasticsearch config as shown at https://docs.securityonion.net/en/2.3/elasticsearch.html.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "### soup has been served at $(date) ###"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while getopts ":b:f:y" opt; do
|
||||||
|
case ${opt} in
|
||||||
|
b )
|
||||||
|
BATCHSIZE="$OPTARG"
|
||||||
|
if ! [[ "$BATCHSIZE" =~ ^[1-9][0-9]*$ ]]; then
|
||||||
|
echo "Batch size must be a number greater than 0."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
y )
|
||||||
|
if [[ ! -f /opt/so/state/yeselastic.txt ]]; then
|
||||||
|
echo "Cannot run soup in unattended mode. You must run soup manually to accept the Elastic License."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
UNATTENDED=true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
f )
|
||||||
|
ISOLOC="$OPTARG"
|
||||||
|
;;
|
||||||
|
\? )
|
||||||
|
echo "Usage: soup [-b] [-y] [-f <iso location>]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
: )
|
||||||
|
echo "Invalid option: $OPTARG requires an argument"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
if [[ -z $UNATTENDED ]]; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
SOUP - Security Onion UPdater
|
SOUP - Security Onion UPdater
|
||||||
@@ -889,6 +1139,9 @@ Press Enter to continue or Ctrl-C to cancel.
|
|||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
read input
|
read -r input
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "### Preparing soup at $(date) ###"
|
||||||
main "$@" | tee -a $SOUP_LOG
|
main "$@" | tee -a $SOUP_LOG
|
||||||
|
|
||||||
|
|||||||
29
salt/curator/files/action/so-aws-close.yml
Normal file
29
salt/curator/files/action/so-aws-close.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set cur_close_days = salt['pillar.get']('elasticsearch:index_settings:so-aws:close', 30) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: close
|
||||||
|
description: >-
|
||||||
|
Close aws indices older than {{cur_close_days}} days.
|
||||||
|
options:
|
||||||
|
delete_aliases: False
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: False
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-aws.*|so-aws.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{cur_close_days}}
|
||||||
|
exclude:
|
||||||
29
salt/curator/files/action/so-aws-delete.yml
Normal file
29
salt/curator/files/action/so-aws-delete.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set DELETE_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-aws:delete', 365) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: delete_indices
|
||||||
|
description: >-
|
||||||
|
Delete aws indices when older than {{ DELETE_DAYS }} days.
|
||||||
|
options:
|
||||||
|
ignore_empty_list: True
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-aws.*|so-aws.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ DELETE_DAYS }}
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
|
||||||
24
salt/curator/files/action/so-aws-warm.yml
Normal file
24
salt/curator/files/action/so-aws-warm.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{%- set WARM_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-aws:warm', 7) -%}
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: allocation
|
||||||
|
description: "Apply shard allocation filtering rules to the specified indices"
|
||||||
|
options:
|
||||||
|
key: box_type
|
||||||
|
value: warm
|
||||||
|
allocation_type: require
|
||||||
|
wait_for_completion: true
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: false
|
||||||
|
disable_action: false
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: prefix
|
||||||
|
value: so-aws
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ WARM_DAYS }}
|
||||||
|
|
||||||
29
salt/curator/files/action/so-azure-close.yml
Normal file
29
salt/curator/files/action/so-azure-close.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set cur_close_days = salt['pillar.get']('elasticsearch:index_settings:so-azure:close', 30) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: close
|
||||||
|
description: >-
|
||||||
|
Close azure indices older than {{cur_close_days}} days.
|
||||||
|
options:
|
||||||
|
delete_aliases: False
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: False
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-azure.*|so-azure.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{cur_close_days}}
|
||||||
|
exclude:
|
||||||
29
salt/curator/files/action/so-azure-delete.yml
Normal file
29
salt/curator/files/action/so-azure-delete.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set DELETE_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-azure:delete', 365) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: delete_indices
|
||||||
|
description: >-
|
||||||
|
Delete azure indices when older than {{ DELETE_DAYS }} days.
|
||||||
|
options:
|
||||||
|
ignore_empty_list: True
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-azure.*|so-azure.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ DELETE_DAYS }}
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
|
||||||
24
salt/curator/files/action/so-azure-warm.yml
Normal file
24
salt/curator/files/action/so-azure-warm.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{%- set WARM_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-azure:warm', 7) -%}
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: allocation
|
||||||
|
description: "Apply shard allocation filtering rules to the specified indices"
|
||||||
|
options:
|
||||||
|
key: box_type
|
||||||
|
value: warm
|
||||||
|
allocation_type: require
|
||||||
|
wait_for_completion: true
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: false
|
||||||
|
disable_action: false
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: prefix
|
||||||
|
value: so-azure
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ WARM_DAYS }}
|
||||||
|
|
||||||
29
salt/curator/files/action/so-barracuda-close.yml
Normal file
29
salt/curator/files/action/so-barracuda-close.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set cur_close_days = salt['pillar.get']('elasticsearch:index_settings:so-barracuda:close', 30) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: close
|
||||||
|
description: >-
|
||||||
|
Close barracuda indices older than {{cur_close_days}} days.
|
||||||
|
options:
|
||||||
|
delete_aliases: False
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: False
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-barracuda.*|so-barracuda.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{cur_close_days}}
|
||||||
|
exclude:
|
||||||
29
salt/curator/files/action/so-barracuda-delete.yml
Normal file
29
salt/curator/files/action/so-barracuda-delete.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set DELETE_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-barracuda:delete', 365) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: delete_indices
|
||||||
|
description: >-
|
||||||
|
Delete barracuda indices when older than {{ DELETE_DAYS }} days.
|
||||||
|
options:
|
||||||
|
ignore_empty_list: True
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-barracuda.*|so-barracuda.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ DELETE_DAYS }}
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
|
||||||
24
salt/curator/files/action/so-barracuda-warm.yml
Normal file
24
salt/curator/files/action/so-barracuda-warm.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{%- set WARM_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-barracuda:warm', 7) -%}
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: allocation
|
||||||
|
description: "Apply shard allocation filtering rules to the specified indices"
|
||||||
|
options:
|
||||||
|
key: box_type
|
||||||
|
value: warm
|
||||||
|
allocation_type: require
|
||||||
|
wait_for_completion: true
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: false
|
||||||
|
disable_action: false
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: prefix
|
||||||
|
value: so-barracuda
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ WARM_DAYS }}
|
||||||
|
|
||||||
29
salt/curator/files/action/so-beats-delete.yml
Normal file
29
salt/curator/files/action/so-beats-delete.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set DELETE_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-beats:delete', 365) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: delete_indices
|
||||||
|
description: >-
|
||||||
|
Delete beats indices when older than {{ DELETE_DAYS }} days.
|
||||||
|
options:
|
||||||
|
ignore_empty_list: True
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-beats.*|so-beats.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ DELETE_DAYS }}
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
|
||||||
24
salt/curator/files/action/so-beats-warm.yml
Normal file
24
salt/curator/files/action/so-beats-warm.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{%- set WARM_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-beats:warm', 7) -%}
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: allocation
|
||||||
|
description: "Apply shard allocation filtering rules to the specified indices"
|
||||||
|
options:
|
||||||
|
key: box_type
|
||||||
|
value: warm
|
||||||
|
allocation_type: require
|
||||||
|
wait_for_completion: true
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: false
|
||||||
|
disable_action: false
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: prefix
|
||||||
|
value: so-beats
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ WARM_DAYS }}
|
||||||
|
|
||||||
29
salt/curator/files/action/so-bluecoat-close.yml
Normal file
29
salt/curator/files/action/so-bluecoat-close.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set cur_close_days = salt['pillar.get']('elasticsearch:index_settings:so-bluecoat:close', 30) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: close
|
||||||
|
description: >-
|
||||||
|
Close bluecoat indices older than {{cur_close_days}} days.
|
||||||
|
options:
|
||||||
|
delete_aliases: False
|
||||||
|
timeout_override:
|
||||||
|
continue_if_exception: False
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-bluecoat.*|so-bluecoat.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{cur_close_days}}
|
||||||
|
exclude:
|
||||||
29
salt/curator/files/action/so-bluecoat-delete.yml
Normal file
29
salt/curator/files/action/so-bluecoat-delete.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{%- set DELETE_DAYS = salt['pillar.get']('elasticsearch:index_settings:so-bluecoat:delete', 365) -%}
|
||||||
|
---
|
||||||
|
# Remember, leave a key empty if there is no value. None will be a string,
|
||||||
|
# not a Python "NoneType"
|
||||||
|
#
|
||||||
|
# Also remember that all examples have 'disable_action' set to True. If you
|
||||||
|
# want to use this action as a template, be sure to set this to False after
|
||||||
|
# copying it.
|
||||||
|
actions:
|
||||||
|
1:
|
||||||
|
action: delete_indices
|
||||||
|
description: >-
|
||||||
|
Delete bluecoat indices when older than {{ DELETE_DAYS }} days.
|
||||||
|
options:
|
||||||
|
ignore_empty_list: True
|
||||||
|
disable_action: False
|
||||||
|
filters:
|
||||||
|
- filtertype: pattern
|
||||||
|
kind: regex
|
||||||
|
value: '^(logstash-bluecoat.*|so-bluecoat.*)$'
|
||||||
|
- filtertype: age
|
||||||
|
source: name
|
||||||
|
direction: older
|
||||||
|
timestring: '%Y.%m.%d'
|
||||||
|
unit: days
|
||||||
|
unit_count: {{ DELETE_DAYS }}
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user