diff --git a/.github/DISCUSSION_TEMPLATE/3-0.yml b/.github/DISCUSSION_TEMPLATE/3-0.yml index 52c3144c2..53cf4c487 100644 --- a/.github/DISCUSSION_TEMPLATE/3-0.yml +++ b/.github/DISCUSSION_TEMPLATE/3-0.yml @@ -14,6 +14,7 @@ body: - 3.2.0 - 3.3.0 - 3.4.0 + - 3.5.0 - Other (please provide detail below) validations: required: true diff --git a/.github/workflows/pythontest.yml b/.github/workflows/pythontest.yml index 5d474f5df..7e5c2742e 100644 --- a/.github/workflows/pythontest.yml +++ b/.github/workflows/pythontest.yml @@ -6,6 +6,7 @@ on: - "salt/sensoroni/files/analyzers/**" - "salt/manager/tools/sbin/**" - "salt/_beacons/**" + - "salt/elastalert/files/modules/**" - "salt/telegraf/tools/sbin_jinja/**" - "salt/telegraf/defaults.yaml" - "salt/telegraf/soc_telegraf.yaml" @@ -18,7 +19,7 @@ jobs: fail-fast: false matrix: python-version: ["3.14"] - python-code-path: ["salt/sensoroni/files/analyzers", "salt/manager/tools/sbin", "salt/_beacons"] + python-code-path: ["salt/sensoroni/files/analyzers", "salt/manager/tools/sbin", "salt/_beacons", "salt/elastalert/files/modules/so"] steps: - uses: actions/checkout@v3 diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index 68ae7f2c4..6533c2907 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,17 +1,17 @@ -### 3.3.0-20260911 ISO image released on 2026/09/11 +### 3.4.0-20261102 ISO image released on 2026/11/02 ### Download and Verify -3.3.0-20260911 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-3.3.0-20260911.iso +3.4.0-20261102 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-3.4.0-20261102.iso -MD5: 12B18433D3A2198A185892FF79CF638F -SHA1: 2B3C2E1FA7A78ED1F956E7EDCC12E32593C14EEE -SHA256: 0938C73B76CE30EC9E4394D312C79EA7CAC721B6818541697279A6221F7D870D +MD5: FB0380AE996E175D6CC7E7A35D8CC178 +SHA1: D8960F1DA352710BCA209773BF0B3AE8791D0D1B +SHA256: DFC4C87668836852A328EC7A0B755C8C1511FF0E43D423DEE23047A95F676D99 Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.3.0-20260911.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.4.0-20261102.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/main/KEYS @@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/ Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.3.0-20260911.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.4.0-20261102.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-3.3.0-20260911.iso +wget https://download.securityonion.net/file/securityonion/securityonion-3.4.0-20261102.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-3.3.0-20260911.iso.sig securityonion-3.3.0-20260911.iso +gpg --verify securityonion-3.4.0-20261102.iso.sig securityonion-3.4.0-20261102.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Fri 11 Sep 2026 11:23:56 AM EDT using RSA key ID FE507013 +gpg: Signature made Sat 31 Oct 2026 09:27:50 AM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. diff --git a/VERSION b/VERSION index 18091983f..1545d9665 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4.0 +3.5.0 diff --git a/salt/ca/files/blocklist/emsign-ecc-root-ca-c3.pem b/salt/ca/files/blocklist/emsign-ecc-root-ca-c3.pem new file mode 100644 index 000000000..517c0e1cf --- /dev/null +++ b/salt/ca/files/blocklist/emsign-ecc-root-ca-c3.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-ecc-root-ca-g3.pem b/salt/ca/files/blocklist/emsign-ecc-root-ca-g3.pem new file mode 100644 index 000000000..060e943bf --- /dev/null +++ b/salt/ca/files/blocklist/emsign-ecc-root-ca-g3.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-root-ca-c1.pem b/salt/ca/files/blocklist/emsign-root-ca-c1.pem new file mode 100644 index 000000000..02bd4a71f --- /dev/null +++ b/salt/ca/files/blocklist/emsign-root-ca-c1.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-root-ca-c2.pem b/salt/ca/files/blocklist/emsign-root-ca-c2.pem new file mode 100644 index 000000000..78025196d --- /dev/null +++ b/salt/ca/files/blocklist/emsign-root-ca-c2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIKLwq3aw3LSq8nWDANBgkqhkiG9w0BAQwFADBWMQswCQYD +VQQGEwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJ +bmMxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0gQzIwHhcNMTgwMjE4MTgzMDAw +WhcNNDMwMjE4MTgzMDAwWjBWMQswCQYDVQQGEwJVUzETMBEGA1UECxMKZW1TaWdu +IFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxHDAaBgNVBAMTE2VtU2lnbiBSb290 +IENBIC0gQzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCMfX1lA+Tb +mh9YInmRgOW97IVx4LUJf2DRZfs837Jrml+py64aVnYgWO4t6C78fgjfS7jX+c4T +inIzEquWcI+zi0fd4Sc8NDf7JONp27VWX0qwUYqzLDRCt+s7zpLcfx1ky0zVIJj6 +L06uPyK3kIr9+YAsrVj+39utm6e2MBQsRNstSI3fCQYAGvoQTQ8fULauTqNWaYAk +NYFe6HUHHQPp2u1Ua00odMXiD5oRFxLcDnGAcE1I/9E9mLCdkggXijYUmico7+Xw +ZeFoPhva6eIJ5p03Lt3Du5W3EcHR0cJmmY1pyeA36JaXKWRNM9IRjYMVNCcp4jhB +2tIYiZ+LVk8bwQ9/1c23txmv3u97taZlV22NF4ttS1qq3J+MOp0oGULBzpKfRx0q +GVqbPukQNGAjOLIN8KDNQNzbR1iAl2d8H+MSoicBo4Aid8TjLWcNv48oCWL53ZrF +BMTDjaIA6frG1t4IpbnHadA7qCJJe2qpJN6n2eQKAUn6UiQDHPsSqNBlcUhQ4Y/0 +Y0mU5rghm2OB9rXQS1Fb1JRCfJMNnJIm5AUB2+2RWzq5Tgz7SbSho8NsZk0UbQnF +xciqQ9uoVTAsK14Sk9oG8Q3zfsM08cdPoRb0WlIZklR6mKD7L8nH/zfGu8PIJv94 +GGB9RZ9U4A69r3ePmy8MvrzfNxHKtH6svwIDAQABo0IwQDAdBgNVHQ4EFgQUs/eK +pNYPiABZ6FEXT9V+7IYigZ0wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADQlpiWM0cv2nZ0H5jVsBq0x2q62Q0LwqATs +CFvyub7gxNCytRuoA8stmPOEu/lg8Igxj4FIjoyhIrWUVxyiLU7No4P+WjEUOwUT +xIpkEOtvGUQ9fiOlcGHtIZDNBlZq7WpktXAxeV55RPPsor26p2FNAMRFfZQh0sLX +hKgk8iulSSggqx8ezgPye63FaiYEi4c/dzRj3HOCnsZiwZZU02df5YpNFjxSwZvE +41cjGpsrpWMfQFI2s53RbeXp47lSAxYE4NzjBFMe+EwFuEveBCJBEAH5rvYu3pi2 +orsJ424TqWEQV1tCsCkQz+Yq/Okal7yHAkKDeOXcP7oN4A+TdXc2pdqxuVCnBO0R +mWz2JpGSSeJjiTk/OPwRsPNWtwG/KXL04o2ta3jiPpJuICVtWDAc9R3auBEgJl5r +ShRmBdszG0LmzsHuZPCFSYC15RBDCOBsa8bDRJ8pBFU2Wi/CVXCACEuavgoveA4F +a5bt38o0PWxsBP+MpocCdVtDMqzQhxy9IohKuXWAGresoIvKDg3xFk6rBOrjfVwJ +elwi/xAisojHPJVQv9W1zVIoHp+EQg/4MQC21NbIX2RoioB+V3hK439b/w7deU8x +2M8cl1OG0nPfbnARl5GPM7vJgi470jto4SeMg6HMAW3Egb56tQcNLwI9U8mZnNvR +gUMrkAgL +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-root-ca-g1.pem b/salt/ca/files/blocklist/emsign-root-ca-g1.pem new file mode 100644 index 000000000..c50d2e6d1 --- /dev/null +++ b/salt/ca/files/blocklist/emsign-root-ca-g1.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-root-ca-g2.pem b/salt/ca/files/blocklist/emsign-root-ca-g2.pem new file mode 100644 index 000000000..b24d764ad --- /dev/null +++ b/salt/ca/files/blocklist/emsign-root-ca-g2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFlTCCA32gAwIBAgILAIZNvw/jXtd9jtgwDQYJKoZIhvcNAQEMBQAwZzELMAkG +A1UEBhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEg +VGVjaG5vbG9naWVzIExpbWl0ZWQxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0g +RzIwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBnMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMNwGIWW2kHfHK+sXTNwxF07K+IV +ySTuyFM2r1v002wUfcdT+zs5OM5QbMYFFnedXQI6gCFLsjKrcaej48Zt37OyEb3i +aPs7CsP4kAyTwzKH9aZe6gXYHrJq40/ZVMNcQVI2PcIp40B/SAN2gUZ+ZaUtIOvV +jEx26/ebNaXRIsthlkOG/caB+QRwDw1tl7338Zlv0M2oTBUy4B3e7dGP5pgXH71M +jqHPCoNo+xv9f0NTBT+hUDa8h8wUtcGQq9CDeJTpjWcD2bP2AMdVG6oVpMAUeUzo +cCyglvtFdUMjggxBbw4qhau1HXPG8Ot9hwL7ZMi8tkTzrvUIxxb8G9LF/7kKeCE7 +tGZaVzDTnXuifl3msR4ErHsQ4P7lVu2AIjIAhrAXoedDidb7pMcf7TABdrYUT1Jo +G/AiK+J9jO6GTjeADD4LMDSBZhHMuBK/PJ/g0kGBt+/C1L+/HURzQhJkMlRnM6Rv +XoCtfKopSlns5trZmTi971Wjbn88QXP61lGpBCUPwCjs7rpOYvSUJtI+lcbF+37q +kIqOXYkVT3cupDSpw+H89kFtj5GKY+Xny4LxY+3IvDIRiyd6ky1DPj713DI0yqve +EpsIr3A0PdwuyUI7CS1jg0NnGFT6Xxyr0xB+VDt83FJYW8v16k2pbaQ4kVxA3aXd +X9dZYyVR1S59KM75AgMBAAGjQjBAMB0GA1UdDgQWBBTt7E1FYRgo57MjKBEcTaUn +DV7s9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQwFAAOCAgEACFC/ilQg8KTCVBxFJW/sazomkS0kNYbEIZg4B3obqwsJ7SX98z8Z +gfzBpz0nYClwwJjWbFN1R2zY8pCEot6/dgmA8Vbq0GxhwPM5YN/SZquNyRIxO3cU +dlAcwf+vSezdVCf9wOzvSAF3q0a5ljvbdbNJNpfScQVp7UUd5sBsZk8jXO1KQ/go +/Vf/GDPnrIFmxpAIGE3sgnO8lAv9FzUaAeuv7HWe47xN9J7+bQzF93yHuIXACPTL +pQHhg2zMv5C7BAbuDHfbj1Cu294Z832yhSfBcziWGskOvl3es2EcHytbS9c9P+0z +Mpka7zGC1FHrvLb/FoduH86TeZt0QjZ6pcplNzoaxDnDvzTJ6CC2Eny+qH/APFCu +VUv5/wjwF+HPm8Pup2ARj9cEp92+0qcerfHacNq5hMeGZdbA/dzdUR/5z5zXdxAk +nl8mcfGb0eMNSTXQmmB/i4AecNnr72uYjzlaXUGYN7Nrb6XouG0pnh0/BBtWWp0U +ShIPpWEAqs7RJBj6+1ZUYXZ4ObrCw962DxhN2p19Hxw9LtuUUcLqqTPrFXYvwO4t +ouj7KJnAkaTUfXGdEaFVtFig1EA30WzJY2X1vAQ7hVnniCjgaXAGqjsU6sklNM9n +xDx5rFCCCEtj9Kh8UHjGK2QqgP5kwgttjOApQMaCoezMfK4KD7WpOXU= +-----END CERTIFICATE----- diff --git a/salt/ca/files/blocklist/emsign-root-cs-ca-g2.pem b/salt/ca/files/blocklist/emsign-root-cs-ca-g2.pem new file mode 100644 index 000000000..c2bd264fe --- /dev/null +++ b/salt/ca/files/blocklist/emsign-root-cs-ca-g2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFdjCCA16gAwIBAgIQCIYhdXKnxAzDuy7l1y1ubDANBgkqhkiG9w0BAQwFADBV +MQswCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGlt +aXRlZDEfMB0GA1UEAwwWZW1TaWduIFJvb3QgQ1MgQ0EgLSBHMjAeFw0yNDAyMDgw +ODE1MzlaFw00OTAyMDcwODE1MzlaMFUxCzAJBgNVBAYTAklOMSUwIwYDVQQKDBxl +TXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMR8wHQYDVQQDDBZlbVNpZ24gUm9v +dCBDUyBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4CVO +xuBjdLJXpkrjosA+7ygTGaYzufUJrhQOeIZEuCqeCPI8hDqIu+MIqEqOlgDFetVM +3Cor3CGBlGJzfzzlI31vyElvQq88jjCfo12Ghqcf+NAZDFduJk5+NgC0z3lfdiB6 +NNzxbfVkA+X6oDNNRioVUZsVFuIzT9Qt0Sh4KwQPRFBc/wI2yGpDuKHNsLehcECx +Uw00m33xGYh9UkeL3reOmAaLYWZiO+Pd2vxPtrkXI4wyN4BMlESJ73uP0tyX9lq4 +M4yN2yh3i+ETI8/jzPjxHD7QFaVkCoS+uj2YmBa3mytlqlBgyOoKueNeotX8hfzB +FNm962abpV4mN0SoC6hjkYv8IayseRPFv9VI0meQXg9OLRoNvBOqG5kw937FH0Li +q3CIzKyvdyeYRT0LJdWA2iuB9l+4zzIfCwGyT4M4VDmJuPBhrTmjXKae6AUtm1eO +q2f8gftA6J6AlbD0gRd/t8CrFssFNm+LYAEd36kWRBuolbaOfbSbEww84xNAgj4U +SPwYjtNDsCkQjtgSOaDtDOmolN+Mbk528Y+LHMlbd4T3Xmp+VIWp5+70GhBDOA91 +hhtims+hHkXjRI2U7WrJLcTlcF8ykiymRbFKhwOBvTmtZNbHmDI7scU4wWUAsmW6 +tWaeeoM50KBl8ai28A6yBGYMO//03Ubvqiqst80CAwEAAaNCMEAwHQYDVR0OBBYE +FOYcxqontIvyvYVkX6/0unKm0AF1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQCv5Asord7fdQMT30emwb+oLuDUxdmJ +DQHnzxIXoNvymDTbNHF9LqjeXc+X+XcjIV8PTp4o2I9wyVppHmcaVgRjN/G9FxeN +5tCQ97v5sdx4eAdPljK1xqg7Vhfmzcp+7rSjJG7Sn9gMlZx81kL3Oa2qZj+W5Fi6 +tN4vaR9OLEyvKKHDG/eFxS/qghD1d/Clkb7UGGjBcWJlaZTWVALMKG+QCxiMoELi +oeKaoBbZoXooxfF0mWdkIl9RWNU4r9O/yt66LBE9rj49dX19L+rGg71/4bTi5ua+ ++Wz60XaOc2CdHJaBSols5hWEx/LBjS7UzfU3uJfnpQXVDi0US5sFzIHIlS6kjh7h +YuF4+/9ZAl4Bx3w2TNN7pVm7I39pgYl7XN6KZRwfkAv4aRswPqhWbQfr3+qfcC93 +cgTyFy2RG5YE/OfmpSs6VtYKawqsdEODz/p2nhZfSDrVDnEPvERqahttY5+gaWNc +2fbibgKMfuejTZaJ3yttPslVSko5SDs0xKU423swu34sb/fdISqtOu4NzPCZiHSG +ladaoITmSA6UWFk4fdqaLBI+xSxY5Et3S1APp5r3j/l1KrWPNbb1/+ydHN+YLbh8 +hCBIecKdk6VbnnFRlulm0d2RSgpfCRrWLomN8JHCxCMVv/hBQXz3AXGM1ZlfYTyl +E1BpDby0G2eEkw== +-----END CERTIFICATE----- diff --git a/salt/ca/init.sls b/salt/ca/init.sls index 3a0fdf91c..381064f2c 100644 --- a/salt/ca/init.sls +++ b/salt/ca/init.sls @@ -10,3 +10,4 @@ include: - ca.server {% endif %} - ca.trustca + - ca.trust diff --git a/salt/ca/trust.map.jinja b/salt/ca/trust.map.jinja new file mode 100644 index 000000000..0ea3002bb --- /dev/null +++ b/salt/ca/trust.map.jinja @@ -0,0 +1,12 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{# Containers mount the extracted directory rather than single files: update-ca-trust replaces + files by rename, so a file bind mount would keep pointing at the old inode. #} +{% set CATRUST = { + 'dir': '/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro', + 'java': '/etc/pki/ca-trust/extracted/java/cacerts', + 'pem': '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem' +} %} diff --git a/salt/ca/trust.sls b/salt/ca/trust.sls new file mode 100644 index 000000000..d138fec7a --- /dev/null +++ b/salt/ca/trust.sls @@ -0,0 +1,37 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +ca_trust_anchor: + file.managed: + - name: /etc/pki/ca-trust/source/anchors/so-intca.crt + - source: salt://ca/files/ca.crt + - show_changes: False + - makedirs: True + +ca_trust_legacy_anchor: + file.absent: + - name: /etc/pki/ca-trust/source/anchors/ca.crt + +ca_trust_legacy_bundles: + file.absent: + - name: /opt/so/conf/ca + +# clean removes blocklist entries that are no longer shipped +ca_trust_blocklist: + file.recurse: + - name: /etc/pki/ca-trust/source/blocklist + - source: salt://ca/files/blocklist + - clean: True + - makedirs: True + - file_mode: '0644' + - dir_mode: '0755' + +ca_trust_extract: + cmd.run: + - name: update-ca-trust extract + - onchanges: + - file: ca_trust_anchor + - file: ca_trust_legacy_anchor + - file: ca_trust_blocklist diff --git a/salt/common/tools/sbin/so-log-check b/salt/common/tools/sbin/so-log-check index 852592a10..73e7feedc 100755 --- a/salt/common/tools/sbin/so-log-check +++ b/salt/common/tools/sbin/so-log-check @@ -178,6 +178,7 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Missing ory_kratos_session cookie" # expected WARN log lines indicating invalid auth header EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Static assets preprocessor only supports GET and HEAD requests" # expected WARN log lines indicating invalid auth header EXCLUDED_ERRORS="$EXCLUDED_ERRORS|respondError" # respondError is a function name, output via http middleware as standard request logging + EXCLUDED_ERRORS="$EXCLUDED_ERRORS|GET /kibana/" # Ignore Kibana queries with triggered words fi if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then diff --git a/salt/desktop/packages.sls b/salt/desktop/packages.sls index b2a028e60..13704b02b 100644 --- a/salt/desktop/packages.sls +++ b/salt/desktop/packages.sls @@ -438,6 +438,10 @@ install_networkminer: pkg.latest: - name: securityonion-networkminer +install_so_crates: + pkg.latest: + - name: securityonion-so-crates + {% else %} desktop_packages_os_fail: diff --git a/salt/desktop/trusted-ca.sls b/salt/desktop/trusted-ca.sls index 5117de1cd..a3a4710f4 100644 --- a/salt/desktop/trusted-ca.sls +++ b/salt/desktop/trusted-ca.sls @@ -1,18 +1,10 @@ - {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'vars/globals.map.jinja' import GLOBALS %} {# we only want this state to run it is CentOS #} {% if GLOBALS.os == 'OEL' %} -trusted_ca: - file.managed: - - name: /etc/pki/ca-trust/source/anchors/ca.crt - - source: salt://ca/files/ca.crt - -update_ca_certs: - cmd.run: - - name: update-ca-trust - - onchanges: - - file: trusted_ca +include: + - ca.trust {% else %} diff --git a/salt/elastalert/defaults.yaml b/salt/elastalert/defaults.yaml index 393932992..1986fdce3 100644 --- a/salt/elastalert/defaults.yaml +++ b/salt/elastalert/defaults.yaml @@ -10,7 +10,7 @@ elastalert: buffer_time: minutes: 10 old_query_limit: - minutes: 5 + minutes: 1440 es_port: 9200 es_conn_timeout: 55 max_query_size: 5000 diff --git a/salt/elastalert/enabled.sls b/salt/elastalert/enabled.sls index 8aa9d4b3f..c2469e91c 100644 --- a/salt/elastalert/enabled.sls +++ b/salt/elastalert/enabled.sls @@ -6,9 +6,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - elastalert.config - elastalert.sostatus @@ -28,6 +30,7 @@ so-elastalert: - ipv4_address: {{ DOCKERMERGED.containers['so-elastalert'].ip }} - detach: True - binds: + - {{ CATRUST.dir }} - /opt/so/rules/elastalert:/opt/elastalert/rules/:ro - /opt/so/log/elastalert:/var/log/elastalert:rw - /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro @@ -46,8 +49,9 @@ so-elastalert: - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKERMERGED.containers['so-elastalert'].extra_env %} - environment: + - REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt + {% if DOCKERMERGED.containers['so-elastalert'].extra_env %} {% for XTRAENV in DOCKERMERGED.containers['so-elastalert'].extra_env %} - {{ XTRAENV }} {% endfor %} @@ -65,6 +69,7 @@ so-elastalert: - file: elastacustmodulesdir - file: elastaconf - watch: + - cmd: ca_trust_extract - file: elastaconf - onlyif: - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 9" {# only run this state if elasticsearch is version 9 #} diff --git a/salt/elastalert/files/modules/so/conftest.py b/salt/elastalert/files/modules/so/conftest.py new file mode 100644 index 000000000..2220e0a7e --- /dev/null +++ b/salt/elastalert/files/modules/so/conftest.py @@ -0,0 +1,80 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +from datetime import datetime +import json +import logging +import sys +import types + +# stand-ins when ElastAlert isn't installed (CI) +try: + import elastalert.alerts # noqa: F401 +except ImportError: + + class Alerter: + def __init__(self, rule): + self.rule = rule + + class DateTimeEncoder(json.JSONEncoder): + def default(self, obj): + return obj.isoformat() if hasattr(obj, 'isoformat') else json.JSONEncoder.default(self, obj) + + class EAException(Exception): + pass + + def lookup_es_key(doc, term): + for part in term.split('.'): + if not isinstance(doc, dict) or part not in doc: + return None + doc = doc[part] + return doc + + def ts_to_dt(value): + return value if isinstance(value, datetime) else datetime.fromisoformat(value) + + def elasticsearch_client(conf): + return None # tests set the alerter's client + + alerts = types.ModuleType('elastalert.alerts') + alerts.Alerter = Alerter + alerts.DateTimeEncoder = DateTimeEncoder + util = types.ModuleType('elastalert.util') + util.EAException = EAException + util.elastalert_logger = logging.getLogger('elastalert') + util.lookup_es_key = lookup_es_key + util.ts_to_dt = ts_to_dt + util.elasticsearch_client = elasticsearch_client + package = types.ModuleType('elastalert') + package.alerts = alerts + package.util = util + sys.modules.update({'elastalert': package, 'elastalert.alerts': alerts, 'elastalert.util': util}) + +# stand-ins when elasticsearch-py isn't installed (CI) +try: + import elasticsearch.exceptions # noqa: F401 +except ImportError: + + class ElasticsearchException(Exception): + pass + + class TransportError(ElasticsearchException): + pass + + class ConnectionError(TransportError): + pass + + class ConflictError(TransportError): + pass + + class RequestError(TransportError): + pass + + exceptions = types.ModuleType('elasticsearch.exceptions') + for cls in (ElasticsearchException, TransportError, ConnectionError, ConflictError, RequestError): + setattr(exceptions, cls.__name__, cls) + es_package = types.ModuleType('elasticsearch') + es_package.exceptions = exceptions + sys.modules.update({'elasticsearch': es_package, 'elasticsearch.exceptions': exceptions}) diff --git a/salt/elastalert/files/modules/so/securityonion-es.py b/salt/elastalert/files/modules/so/securityonion-es.py index d9bb8009e..8104661e5 100644 --- a/salt/elastalert/files/modules/so/securityonion-es.py +++ b/salt/elastalert/files/modules/so/securityonion-es.py @@ -1,63 +1,269 @@ # -*- coding: utf-8 -*- # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - -from time import gmtime, strftime -import requests,json -from elastalert.alerts import Alerter +from datetime import datetime, timezone +import hashlib +import ipaddress +import json +import re +import uuid import urllib3 +from elasticsearch.exceptions import ConflictError, ElasticsearchException, RequestError +from elastalert.alerts import Alerter, DateTimeEncoder +from elastalert.util import EAException, elastalert_logger, elasticsearch_client, lookup_es_key, ts_to_dt + +# grid runs verify_certs: false; also quiets ElastAlert's own queries urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) +ALERT_INDEX = 'logs-detections.alerts-so' +# ES error text kept in logs and alerts +ERROR_TEXT_LIMIT = 500 +# a match missing backend columns (window_start, count, @timestamp); the alert is still written +MATCH_ERRORS = (KeyError, TypeError, ValueError) + + class SecurityOnionESAlerter(Alerter): """ Use matched data to create alerts in Elasticsearch. """ - required_options = set(['detection_title', 'sigma_level']) - optional_fields = ['sigma_category', 'sigma_product', 'sigma_service'] + required_options = {'detection_title', 'sigma_level'} + optional_fields = ['sigma_category', 'sigma_product', 'sigma_service', 'sigma_correlation'] + + # count column and default summary per type; stored alert data, so not localized + CORRELATION_COUNTS = { + 'event_count': ('event_count', '%count% events'), + 'value_count': ('value_count', '%count% distinct values'), + 'temporal': ('event_type_count', '%count% correlated rules matched'), + 'value_sum': ('value_sum', 'total %count%'), + 'value_avg': ('value_avg', 'average %count%'), + 'value_percentile': ('value_percentile', 'percentile %count%'), + 'value_median': ('value_median', 'median %count%'), + } + PLACEHOLDER = re.compile(r'%([^%\s]+)%') + # group-by fields copied into ECS related.* + RELATED_USERS = {'user.name', 'winlog.event_data.TargetUserName', 'winlog.event_data.SubjectUserName'} + RELATED_HOSTS = {'host.name', 'host.hostname', 'winlog.computer_name'} + + def __init__(self, rule): + super().__init__(rule) + # uses the grid's TLS, auth and timeout settings + self.es = elasticsearch_client(rule) + + @property + def is_correlation(self): + return bool(self.rule.get('sigma_correlation')) + + def query_keys(self): + """compound_query_key holds the list; query_key is flattened to a string.""" + if self.rule.get('compound_query_key'): + return self.rule['compound_query_key'] + if self.rule.get('query_key'): + return [self.rule['query_key']] + return [] + + def alert_id(self, match): + """Stable id: window end + group values for correlations, source _id otherwise; random without one.""" + if self.is_correlation: + # ungrouped rows have a hashed _id that changes with the count + values = ''.join(f"|{lookup_es_key(match, k)}" for k in self.query_keys()) + key = f"{self.rule['detection_public_id']}|{ts_to_dt(match['@timestamp']).isoformat()}{values}" + elif match.get('_id'): + key = f"{self.rule['detection_public_id']}|{match['_id']}" + else: + return uuid.uuid4().hex + + return hashlib.sha256(key.encode('utf-8')).hexdigest() + + def group(self, match): + """Group-by values, joined like ElastAlert's realert key.""" + return ', '.join(str(lookup_es_key(match, k)) for k in self.query_keys()) + + def related_bucket(self, key): + if key == 'ip' or key.endswith('.ip'): + return 'ip' + if key in self.RELATED_USERS or key.endswith('.user.name'): + return 'user' + if key in self.RELATED_HOSTS: + return 'hosts' + return None + + @staticmethod + def valid_ip(value): + try: + ipaddress.ip_address(value) + return True + except ValueError: + return False + + def related(self, match): + """ECS related.* from group-by values; skips invalid IPs.""" + related = {} + for key in self.query_keys(): + bucket = self.related_bucket(key) + if not bucket: + continue + # original spellings of a lowercased group + value = lookup_es_key(match, f"{key}_spellings") + if value is None: + value = lookup_es_key(match, key) + for v in value if isinstance(value, list) else [value]: + if v is None or (bucket == 'ip' and not self.valid_ip(str(v))): + continue + # dict: ordered and deduped + related.setdefault(bucket, {})[str(v)] = None + return {bucket: list(values) for bucket, values in related.items()} + + def event_data(self, match): + """The match minus the compound query_key field, which ES would map by its last part.""" + if not self.rule.get('compound_query_key'): + return match + return {k: v for k, v in match.items() if k != self.rule['query_key']} + + @staticmethod + def format_value(value): + if isinstance(value, list): + shown = ', '.join(str(v) for v in value[:3]) + return shown if len(value) <= 3 else f"{shown} and {len(value) - 3} more" + return str(value) + + @staticmethod + def format_count(value): + if isinstance(value, float) and not value.is_integer(): + return f"{value:,.2f}" + if isinstance(value, (int, float)): + return f"{int(value):,}" + return str(value) + + @staticmethod + def format_duration(seconds): + for unit, size in (('hour', 3600), ('minute', 60)): + if seconds >= 2 * size: + return f"{seconds // size} {unit}s" + return f"{seconds} second{'' if seconds == 1 else 's'}" + + def summary(self, match): + """One-line correlation summary.""" + column, label = self.CORRELATION_COUNTS.get(self.rule['sigma_correlation'], (None, '%count%')) + start = ts_to_dt(match['window_start']) + end = ts_to_dt(match['@timestamp']) + values = { + 'count': self.format_count(match.get(column)), + 'start': start.strftime('%Y-%m-%d %H:%M:%S UTC'), + 'end': end.strftime('%Y-%m-%d %H:%M:%S UTC'), + 'duration': self.format_duration(int((end - start).total_seconds())), + } + + template = self.rule.get('summary_template') + if not template: + groups = ', '.join(f"{k} %{k}%" for k in self.query_keys()) + template = f"{label} for {groups} in %duration%" if groups else f"{label} in %duration%" + + def fill(m): + if m[1] in values: + return values[m[1]] + value = lookup_es_key(match, m[1]) + # unknown placeholders stay visible so typos show + return m[0] if value is None else self.format_value(value) + + return self.PLACEHOLDER.sub(fill, template) def alert(self, matches): for match in matches: - timestamp = strftime("%Y-%m-%d"'T'"%H:%M:%S"'.000Z', gmtime()) - headers = {"Content-Type": "application/json"} + try: + alert_id = self.alert_id(match) + except MATCH_ERRORS as e: + elastalert_logger.warning("Writing alert for rule %s without a stable id, so a retry may duplicate it: %r", + self.rule['detection_public_id'], e) + alert_id = uuid.uuid4().hex + try: + self.write(alert_id, self.payload(match)) + except ElasticsearchException as e: + # EAException makes ElastAlert retry + raise EAException(f"Unable to write the alert to Elasticsearch: {str(e)[:ERROR_TEXT_LIMIT]}") from e - creds = None - if 'es_username' in self.rule and 'es_password' in self.rule: - creds = (self.rule['es_username'], self.rule['es_password']) + def payload(self, match): + rule_info = { + "name": self.rule['detection_title'], + "uuid": self.rule['detection_public_id'] + } - # Start building the rule dict - rule_info = { - "name": self.rule['detection_title'], - "uuid": self.rule['detection_public_id'] - } + # Add optional fields if they are present in the rule + for field in self.optional_fields: + rule_key = field.split('_')[-1] # Assumes field format "sigma_" + if field in self.rule: + rule_info[rule_key] = self.rule[field] - # Add optional fields if they are present in the rule - for field in self.optional_fields: - rule_key = field.split('_')[-1] # Assumes field format "sigma_" - if field in self.rule: - rule_info[rule_key] = self.rule[field] + event_info = { + "kind": "alert", + "severity": self.rule['event.severity'], + "module": self.rule['event.module'], + "dataset": self.rule['event.dataset'], + "severity_label": self.rule['sigma_level'] + } - # Construct the payload with the conditional rule_info - payload = { - "tags": "alert", - "rule": rule_info, - "event": { - "severity": self.rule['event.severity'], - "module": self.rule['event.module'], - "dataset": self.rule['event.dataset'], - "severity_label": self.rule['sigma_level'] - }, - "sigma_level": self.rule['sigma_level'], - "event_data": match, - "@timestamp": timestamp - } - url = f"https://{self.rule['es_host']}:{self.rule['es_port']}/logs-detections.alerts-so/_doc/" - requests.post(url, data=json.dumps(payload), headers=headers, verify=False, auth=creds) + payload = { + "tags": ["alert"], + "rule": rule_info, + "event": event_info, + "sigma_level": self.rule['sigma_level'], + "event_data": self.event_data(match), + "@timestamp": datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z') + } + + if self.is_correlation: + keys = self.query_keys() + try: + # built before any is added, so a failure adds none + reason = self.summary(match) + labels = {"correlation_group_by": ', '.join(keys), "correlation_group": self.group(match)} if keys else None + related = self.related(match) + except MATCH_ERRORS as e: + elastalert_logger.warning("Writing alert for rule %s without its correlation summary: %r", + self.rule['detection_public_id'], e) + else: + payload["event"]["reason"] = reason + if labels: + payload["labels"] = labels + if related: + payload["related"] = related + + return payload + + def write(self, alert_id, payload): + try: + self.create(alert_id, payload) + except RequestError as e: + # mapping rejections come from event_data; retry it as text + rejection = str(e)[:ERROR_TEXT_LIMIT] + try: + self.create(alert_id, self.without_event_data(payload, rejection)) + except RequestError as again: + elastalert_logger.error("Dropping alert %s for rule %s, rejected by Elasticsearch even without its event data: %s; first rejection: %s", + alert_id, self.rule['detection_public_id'], str(again)[:ERROR_TEXT_LIMIT], rejection) + return + elastalert_logger.warning("Stored alert %s for rule %s with its event data as text, rejected by Elasticsearch: %s", + alert_id, self.rule['detection_public_id'], rejection) + + def create(self, alert_id, payload): + try: + self.es.create(index=ALERT_INDEX, id=alert_id, body=payload) + except ConflictError: + pass # a repeat id is already stored + + @staticmethod + def without_event_data(payload, rejection): + """Moves event_data to event.original; the tag keeps Fleet's final pipeline from dropping it.""" + fallback = {k: v for k, v in payload.items() if k != 'event_data'} + fallback['event'] = dict(payload['event'], original=json.dumps(payload['event_data'], cls=DateTimeEncoder)) + fallback['error'] = {'message': f"event_data rejected by Elasticsearch: {rejection}"} + fallback['tags'] = payload['tags'] + ['preserve_original_event'] + return fallback def get_info(self): return {'type': 'SecurityOnionESAlerter'} diff --git a/salt/elastalert/files/modules/so/securityonion-es_test.py b/salt/elastalert/files/modules/so/securityonion-es_test.py new file mode 100644 index 000000000..bfdce060f --- /dev/null +++ b/salt/elastalert/files/modules/so/securityonion-es_test.py @@ -0,0 +1,260 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import copy +from datetime import datetime, timezone +import importlib.util +import json +import os +import unittest +from unittest.mock import MagicMock + +from elasticsearch.exceptions import ConflictError, ConnectionError, RequestError + +spec = importlib.util.spec_from_file_location('securityonion_es', os.path.join(os.path.dirname(__file__), 'securityonion-es.py')) +es = importlib.util.module_from_spec(spec) +spec.loader.exec_module(es) + +BASE_RULE = { + 'detection_title': 'Many Failed Network Logons To One Host From One Source', + 'detection_public_id': '35a42db6-6629-45af-b8aa-e1fa33c28ef5', + 'sigma_level': 'medium', + 'sigma_correlation': 'event_count', + 'event.severity': 3, + 'event.module': 'sigma', + 'event.dataset': 'sigma.alert', + 'summary_template': '%count% failed network logons to %host.name% from %source.ip% in %duration%', +} + +PLAIN_RULE = {k: v for k, v in BASE_RULE.items() if k not in ('sigma_correlation', 'summary_template')} + + +def correlation_match(): + return { + 'event_count': 3561, + 'window_start': '2026-09-30T18:05:10+00:00', + '@timestamp': '2026-09-30T18:07:53+00:00', + 'host': {'name': 'host-01'}, + 'source': {'ip': '192.0.2.10'}, + '_id': '6d1c', + 'num_hits': 1, + 'num_matches': 1, + } + + +class TestSecurityOnionESAlerter(unittest.TestCase): + + def creates(self, rule, match, effects=None): + """Run alert(); return (body, id) of each create.""" + alerter = es.SecurityOnionESAlerter(rule) + alerter.es = MagicMock() + alerter.es.create.side_effect = effects + alerter.alert([match]) + calls = alerter.es.create.call_args_list + self.assertTrue(all(c.kwargs['index'] == 'logs-detections.alerts-so' for c in calls)) + return [(json.loads(json.dumps(c.kwargs['body'], cls=es.DateTimeEncoder)), c.kwargs['id']) for c in calls] + + def send(self, rule, match): + """Run alert(); return the payload it wrote and its id.""" + (payload, alert_id), = self.creates(rule, match) + return payload, alert_id + + def test_compound_query_key_left_out_of_event_data(self): + rule = dict(BASE_RULE, compound_query_key=['host.name', 'source.ip'], query_key='host.name,source.ip') + match = correlation_match() + match['host.name,source.ip'] = 'host-01, 192.0.2.10' + original = copy.deepcopy(match) + + payload, _ = self.send(rule, match) + + self.assertNotIn('host.name,source.ip', payload['event_data']) + self.assertEqual(payload['event_data']['host'], {'name': 'host-01'}) + self.assertEqual(payload['event_data']['source'], {'ip': '192.0.2.10'}) + self.assertEqual(payload['rule'], {'name': BASE_RULE['detection_title'], 'uuid': BASE_RULE['detection_public_id'], 'correlation': 'event_count'}) + self.assertEqual(payload['labels'], {'correlation_group_by': 'host.name, source.ip', 'correlation_group': 'host-01, 192.0.2.10'}) + self.assertEqual(payload['related'], {'hosts': ['host-01'], 'ip': ['192.0.2.10']}) + self.assertEqual(payload['event']['kind'], 'alert') + self.assertEqual(payload['event']['reason'], '3,561 failed network logons to host-01 from 192.0.2.10 in 2 minutes') + # ElastAlert reuses the match + self.assertEqual(match, original) + + def test_single_query_key(self): + rule = dict(BASE_RULE, query_key='user.name', summary_template='%count% failed SOC logins for %user.name%') + match = {'event_count': 3, 'window_start': '2026-09-30T16:49:52+00:00', '@timestamp': '2026-09-30T16:50:00+00:00', + 'user': {'name': 'user@example.invalid'}} + + payload, _ = self.send(rule, match) + + self.assertEqual(payload['labels'], {'correlation_group_by': 'user.name', 'correlation_group': 'user@example.invalid'}) + self.assertEqual(payload['related'], {'user': ['user@example.invalid']}) + self.assertEqual(payload['event']['reason'], '3 failed SOC logins for user@example.invalid') + self.assertEqual(payload['event_data'], match) + + def test_related_buckets(self): + rule = dict(BASE_RULE, compound_query_key=['winlog.event_data.TargetUserName', 'source.ip', 'dns.highest_registered_domain'], + query_key='winlog.event_data.TargetUserName,source.ip,dns.highest_registered_domain') + match = correlation_match() + match.update({'winlog': {'event_data': {'TargetUserName': ['admin1', 'svc', 'admin1']}}, + 'source': {'ip': 'not-an-ip'}, 'dns': {'highest_registered_domain': 'example.com'}}) + + payload, _ = self.send(rule, match) + + # deduped; invalid IP skipped; domain stays in the group only + self.assertEqual(payload['related'], {'user': ['admin1', 'svc']}) + self.assertEqual(payload['labels']['correlation_group'], "['admin1', 'svc', 'admin1'], not-an-ip, example.com") + + payload, _ = self.send(dict(BASE_RULE, query_key='dns.highest_registered_domain'), match) + + self.assertNotIn('related', payload) + + def test_related_uses_original_spellings(self): + rule = dict(BASE_RULE, query_key='user.name', summary_template=None) + match = {'event_count': 3, 'window_start': '2026-09-30T16:49:52+00:00', '@timestamp': '2026-09-30T16:50:00+00:00', + 'user': {'name': 'admin', 'name_spellings': ['Admin', 'admin', 'ADMIN']}} + + payload, _ = self.send(rule, match) + + # the group shows the lowercased value; related.user finds every spelling + self.assertEqual(payload['labels']['correlation_group'], 'admin') + self.assertEqual(payload['related'], {'user': ['Admin', 'admin', 'ADMIN']}) + self.assertEqual(payload['event']['reason'], '3 events for user.name admin in 8 seconds') + + def test_plain_rule_has_no_correlation_fields(self): + # a query_key alone (e.g. from an override) isn't a correlation + rule = dict(PLAIN_RULE, query_key='user.name') + # ElastAlert parses @timestamp for EQL hits + match = {'@timestamp': datetime(2026, 9, 30, 16, 50, tzinfo=timezone.utc), '_id': 'abc', + 'process': {'name': 'whoami.exe'}, 'user': {'name': 'user'}} + + payload, alert_id = self.send(rule, match) + + alerter = es.SecurityOnionESAlerter(rule) + self.assertEqual(payload['rule'], {'name': PLAIN_RULE['detection_title'], 'uuid': PLAIN_RULE['detection_public_id']}) + self.assertNotIn('labels', payload) + self.assertNotIn('related', payload) + self.assertNotIn('reason', payload['event']) + self.assertEqual(payload['event']['kind'], 'alert') + self.assertEqual(payload['event_data'], dict(match, **{'@timestamp': '2026-09-30T16:50:00+00:00'})) + self.assertEqual(alert_id, alerter.alert_id(match)) + self.assertNotEqual(alerter.alert_id(match), alerter.alert_id(dict(match, _id='abd'))) + self.assertNotEqual(alerter.alert_id(match), es.SecurityOnionESAlerter(dict(rule, detection_public_id='other')).alert_id(match)) + # without an _id, never deduplicated + self.assertNotEqual(alerter.alert_id({'_id': None}), alerter.alert_id({'_id': None})) + + def test_ungrouped_correlation_id_ignores_row_hash(self): + rule = dict(BASE_RULE, summary_template=None) + first = {k: v for k, v in correlation_match().items() if k not in ('host', 'source')} + # ES|QL hashes the row into _id, so a later count changes it + later = dict(first, event_count=3600, _id='9f2a') + + payload, alert_id = self.send(rule, first) + + alerter = es.SecurityOnionESAlerter(rule) + self.assertEqual(alerter.alert_id(first), alerter.alert_id(later)) + self.assertNotEqual(alerter.alert_id(first), alerter.alert_id(dict(first, **{'@timestamp': '2026-09-30T18:09:00+00:00'}))) + self.assertEqual(alert_id, alerter.alert_id(first)) + self.assertEqual(payload['event']['reason'], '3,561 events in 2 minutes') + self.assertNotIn('labels', payload) + + def test_temporal_count_column(self): + rule = dict(BASE_RULE, sigma_correlation='temporal', summary_template=None) + match = {'event_type_count': 2, 'window_start': '2026-09-30T16:49:52+00:00', '@timestamp': '2026-09-30T16:50:00+00:00'} + + payload, _ = self.send(rule, match) + + self.assertEqual(payload['event']['reason'], '2 correlated rules matched in 8 seconds') + + def test_grouped_correlation_id_unchanged(self): + """Ids of alerts already written must not change.""" + rule = dict(BASE_RULE, compound_query_key=['host.name', 'source.ip'], query_key='host.name,source.ip') + key = f"{BASE_RULE['detection_public_id']}|2026-09-30T18:07:53+00:00|host-01|192.0.2.10" + + self.assertEqual(es.SecurityOnionESAlerter(rule).alert_id(correlation_match()), es.hashlib.sha256(key.encode()).hexdigest()) + + def test_rejected_event_data_is_kept_as_text(self): + rule = dict(BASE_RULE, query_key='user.name', summary_template='%count% failed SOC logins for %user.name%') + match = {'event_count': 3, 'window_start': '2026-09-30T16:49:52+00:00', '@timestamp': '2026-09-30T16:50:00+00:00', + 'user': {'name': 'user@example.invalid'}} + rejected = RequestError(400, 'document_parsing_exception', {}) + + (first, _), (second, _) = self.creates(rule, match, [rejected, None]) + + self.assertIn('event_data', first) + self.assertNotIn('event_data', second) + self.assertEqual(json.loads(second['event']['original']), match) + self.assertEqual(second['tags'], ['alert', 'preserve_original_event']) + self.assertEqual(first['tags'], ['alert']) + self.assertTrue(second['error']['message'].startswith('event_data rejected by Elasticsearch: ')) + self.assertIn('document_parsing_exception', second['error']['message']) + # everything else carries over + self.assertEqual({k: v for k, v in second['event'].items() if k != 'original'}, first['event']) + changed = ('event_data', 'event', 'error', 'tags') + self.assertEqual({k: v for k, v in second.items() if k not in changed}, {k: v for k, v in first.items() if k not in changed}) + + def test_rejected_dates_are_kept_as_text(self): + match = {'@timestamp': datetime(2026, 9, 30, 16, 50, tzinfo=timezone.utc), '_id': 'abc'} + + _, (second, _) = self.creates(PLAIN_RULE, match, [RequestError(400, 'document_parsing_exception', {}), None]) + + self.assertEqual(json.loads(second['event']['original']), {'@timestamp': '2026-09-30T16:50:00+00:00', '_id': 'abc'}) + + def test_rejected_twice_is_dropped_without_retry(self): + rejected = RequestError(400, 'document_parsing_exception', {}) + match = {'@timestamp': '2026-09-30T16:50:00+00:00', '_id': 'abc'} + + with self.assertLogs('elastalert', 'ERROR') as logs: + self.assertEqual(len(self.creates(PLAIN_RULE, match, [rejected, rejected])), 2) + + self.assertIn('Dropping alert', logs.output[0]) + + def test_write_failure_is_retried(self): + match = {'@timestamp': '2026-09-30T16:50:00+00:00', '_id': 'abc'} + + with self.assertRaisesRegex(es.EAException, 'Unable to write the alert to Elasticsearch'): + self.creates(PLAIN_RULE, match, [ConnectionError('N/A', 'refused', None)]) + + def test_repeat_id_is_ignored(self): + match = {'@timestamp': '2026-09-30T16:50:00+00:00', '_id': 'abc'} + + self.assertEqual(len(self.creates(PLAIN_RULE, match, [ConflictError(409, 'version_conflict_engine_exception', {})])), 1) + + def test_correlation_fields_are_optional(self): + rule = dict(BASE_RULE, query_key='source.ip') + # no window_start: the summary cannot be built + match = {k: v for k, v in correlation_match().items() if k != 'window_start'} + + with self.assertLogs('elastalert', 'WARNING') as logs: + payload, _ = self.send(rule, match) + + self.assertIn('without its correlation summary', logs.output[0]) + self.assertEqual(payload['event']['kind'], 'alert') + self.assertNotIn('reason', payload['event']) + self.assertNotIn('labels', payload) + self.assertNotIn('related', payload) + + def test_unstable_id_still_writes(self): + # no @timestamp: the window end is unknown + match = {k: v for k, v in correlation_match().items() if k not in ('@timestamp', 'window_start')} + + with self.assertLogs('elastalert', 'WARNING') as logs: + payload, alert_id = self.send(BASE_RULE, match) + + self.assertIn('without a stable id', logs.output[0]) + self.assertEqual(len(alert_id), 32) + self.assertEqual(payload['event_data'], match) + + def test_summary_formats_values(self): + rule = dict(BASE_RULE, sigma_correlation='value_avg', query_key='source.ip', + summary_template='%count% for %source.ip% to %destination.port% %no.such.field%') + match = {'value_avg': 2.5, 'window_start': '2026-09-30T16:49:52+00:00', '@timestamp': '2026-09-30T16:50:00+00:00', + 'source': {'ip': '192.0.2.10'}, 'destination': {'port': [22, 80, 443, 8080, 8443]}} + + payload, _ = self.send(rule, match) + + self.assertEqual(payload['event']['reason'], '2.50 for 192.0.2.10 to 22, 80, 443 and 2 more %no.such.field%') + self.assertEqual(es.SecurityOnionESAlerter.format_count('n/a'), 'n/a') + + def test_get_info(self): + self.assertEqual(es.SecurityOnionESAlerter(PLAIN_RULE).get_info(), {'type': 'SecurityOnionESAlerter'}) diff --git a/salt/elastalert/soc_elastalert.yaml b/salt/elastalert/soc_elastalert.yaml index 123ead697..3d848e5af 100644 --- a/salt/elastalert/soc_elastalert.yaml +++ b/salt/elastalert/soc_elastalert.yaml @@ -120,7 +120,7 @@ elastalert: helpLink: elastalert old_query_limit: minutes: - description: Amount of time in minutes between queries to start at the most recently run query. + description: How long ElastAlert can be down, in minutes, and still resume each rule where it stopped. After a longer outage, rules restart from now and skip the gap. global: True helpLink: elastalert es_conn_timeout: diff --git a/salt/elastic-fleet-package-registry/enabled.sls b/salt/elastic-fleet-package-registry/enabled.sls index 3bf15c984..82208f003 100644 --- a/salt/elastic-fleet-package-registry/enabled.sls +++ b/salt/elastic-fleet-package-registry/enabled.sls @@ -6,9 +6,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - elastic-fleet-package-registry.config - elastic-fleet-package-registry.sostatus @@ -34,8 +36,9 @@ so-elastic-fleet-package-registry: {% for BINDING in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro + {% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} {% for BIND in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} - {{ BIND }} {% endfor %} @@ -52,6 +55,8 @@ so-elastic-fleet-package-registry: - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} {% endfor %} {% endif %} + - watch: + - cmd: ca_trust_extract wait_for_so-elastic-fleet-package-registry: http.wait_for_successful_query: diff --git a/salt/elasticagent/enabled.sls b/salt/elasticagent/enabled.sls index c6ee02ddf..1e45a91dd 100644 --- a/salt/elasticagent/enabled.sls +++ b/salt/elasticagent/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: @@ -37,6 +38,7 @@ so-elastic-agent: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/elastic-agent/elastic-agent.yml:/usr/share/elastic-agent/elastic-agent.yml:ro - /opt/so/log/elasticagent:/usr/share/elastic-agent/logs - /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro @@ -65,6 +67,7 @@ so-elastic-agent: - file: create-elastic-agent-config - file: trusttheca - watch: + - cmd: ca_trust_extract - file: create-elastic-agent-config - file: trusttheca diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index feb83fc2f..e08170097 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} @@ -63,6 +64,7 @@ so-elastic-fleet: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.dir }} - /etc/pki/elasticfleet-server.crt:/etc/pki/elasticfleet-server.crt:ro - /etc/pki/elasticfleet-server.key:/etc/pki/elasticfleet-server.key:ro - /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro @@ -95,6 +97,7 @@ so-elastic-fleet: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: trusttheca - x509: etc_elasticfleet_key - x509: etc_elasticfleet_crt diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index 559caad5a..ef79f8810 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -30,6 +30,8 @@ 'azure_metrics.monitor': 'azure.monitor', 'azure_metrics.storage_account': 'azure.storage_account', 'azure_openai.metrics': 'azure.open_ai', + 'enterprisesearch.health': 'enterprisesearch.stack_monitoring.health', + 'enterprisesearch.stats': 'enterprisesearch.stack_monitoring.stats', 'kibana.cluster_actions': 'kibana.stack_monitoring.cluster_actions', 'kibana.cluster_rules': 'kibana.stack_monitoring.cluster_rules', 'kibana.node_actions': 'kibana.stack_monitoring.node_actions', diff --git a/salt/elasticsearch/ca.sls b/salt/elasticsearch/ca.sls deleted file mode 100644 index 39d33919c..000000000 --- a/salt/elasticsearch/ca.sls +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls.split('.')[0] in allowed_states or sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} - -# Move our new CA over so Elastic and Logstash can use SSL with the internal CA -catrustdir: - file.directory: - - name: /opt/so/conf/ca - - user: 939 - - group: 939 - - makedirs: True - -{% if GLOBALS.is_manager %} -# We have to add the Manager CA to the CA list -catrustscript: - cmd.script: - - source: salt://elasticsearch/tools/sbin_jinja/so-catrust - - template: jinja - - cwd: /opt/so - - defaults: - GLOBALS: {{ GLOBALS }} -{% endif %} - -elasticsearch_cacerts: - file.managed: - - name: /opt/so/conf/ca/cacerts - - source: salt://elasticsearch/cacerts - - user: 939 - - group: 939 - -elasticsearch_capems: - file.managed: - - name: /opt/so/conf/ca/tls-ca-bundle.pem - - source: salt://elasticsearch/tls-ca-bundle.pem - - user: 939 - - group: 939 - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/elasticsearch/cluster.sls b/salt/elasticsearch/cluster.sls index 45dcf4111..df3314ba1 100644 --- a/salt/elasticsearch/cluster.sls +++ b/salt/elasticsearch/cluster.sls @@ -107,6 +107,12 @@ so-elasticsearch-system-indices-patch: - file: so-elasticsearch-system-indices-patch-script {% endif %} +so-elasticsearch-ilm-policy-reload: + file.absent: + - name: /opt/so/state/esilm.txt + - onchanges: + - file: so-elasticsearch-ilm-policy-load-script + # heavynodes will only load ILM policies for SO managed indices. (Indicies defined in elasticsearch/defaults.yaml) so-elasticsearch-ilm-policy-load: cmd.run: @@ -115,8 +121,9 @@ so-elasticsearch-ilm-policy-load: - require: - docker_container: so-elasticsearch - file: so-elasticsearch-ilm-policy-load-script - - onchanges: - - file: so-elasticsearch-ilm-policy-load-script + - http: wait_for_so-elasticsearch + - file: so-elasticsearch-ilm-policy-reload + - unless: test -f /opt/so/state/esilm.txt so-elasticsearch-templates-reload: file.absent: diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index c8ceab34d..6ec8e21bf 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -1,7 +1,7 @@ elasticsearch: enabled: false esheap: '600m' - version: 9.4.5 + version: 9.4.8 index_clean: true data_retention_method: DLM vm: @@ -1160,6 +1160,7 @@ elasticsearch: - so-fleet_agent_id_verification-1 - so-logs-mappings - so-logs-settings + - detections-alerts-mappings data_stream: allow_custom_routing: false hidden: false diff --git a/salt/elasticsearch/enabled.sls b/salt/elasticsearch/enabled.sls index 48f094d3c..755581ab9 100644 --- a/salt/elasticsearch/enabled.sls +++ b/salt/elasticsearch/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_NODES %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_SEED_HOSTS %} @@ -13,7 +14,6 @@ include: - ca - - elasticsearch.ca - elasticsearch.ssl - elasticsearch.config - elasticsearch.sostatus @@ -63,15 +63,14 @@ so-elasticsearch: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro - /opt/so/conf/elasticsearch/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties:ro - /nsm/elasticsearch:/usr/share/elasticsearch/data:rw - /opt/so/log/elasticsearch:/var/log/elasticsearch:rw - - /opt/so/conf/ca/cacerts:/usr/share/elasticsearch/jdk/lib/security/cacerts:ro - /etc/pki/tls/certs/intca.crt:/usr/share/elasticsearch/config/ca.crt:ro - /etc/pki/elasticsearch.crt:/usr/share/elasticsearch/config/elasticsearch.crt:ro - /etc/pki/elasticsearch.key:/usr/share/elasticsearch/config/elasticsearch.key:ro - - /etc/pki/elasticsearch.p12:/usr/share/elasticsearch/config/elasticsearch.p12:ro - /opt/so/conf/elasticsearch/users_roles:/usr/share/elasticsearch/config/users_roles:ro - /opt/so/conf/elasticsearch/users:/usr/share/elasticsearch/config/users:ro {% if ELASTICSEARCHMERGED.config.path.get('repo', False) %} @@ -85,21 +84,19 @@ so-elasticsearch: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: trusttheca - x509: elasticsearch_crt - x509: elasticsearch_key - - file: elasticsearch_cacerts - file: esyml - require: - file: trusttheca - x509: elasticsearch_crt - x509: elasticsearch_key - - file: elasticsearch_cacerts - file: esyml - file: eslog4jfile - file: nsmesdir - file: eslogdir - - file: elasticp12perms - cmd: auth_users_roles_inode - cmd: auth_users_inode diff --git a/salt/elasticsearch/files/ingest/global@custom b/salt/elasticsearch/files/ingest/global@custom index ab1418cd2..bfd58d750 100644 --- a/salt/elasticsearch/files/ingest/global@custom +++ b/salt/elasticsearch/files/ingest/global@custom @@ -1,5 +1,5 @@ { - "version": 3, + "version": 4, "_meta": { "managed_by": "securityonion", "managed": true @@ -177,6 +177,32 @@ "description": "Extract IPs from Elastic Agent events (host.ip) and adds them to related.ip" } }, + { + "trim": { + "if": "ctx.event?.dataset == 'system.auth'", + "description": "Grok leaves a leading space on 'invalid user' names (elastic/integrations#12174) and, before 2.23.2, sudo padding", + "field": "user.name", + "ignore_missing": true, + "ignore_failure": true + } + }, + { + "trim": { + "if": "ctx.event?.dataset == 'system.auth'", + "description": "Appended from the untrimmed user.name", + "field": "related.user", + "ignore_missing": true, + "ignore_failure": true + } + }, + { + "script": { + "if": "ctx.event?.dataset == 'system.auth' && ctx.related?.user instanceof List", + "description": "Dedupe after trimming", + "source": "ctx.related.user = new ArrayList(new LinkedHashSet(ctx.related.user));", + "ignore_failure": true + } + }, { "script": { "description": "Snapshot event.ingested into _tmp.event_ingested_pre_fleet before .fleet_final_pipeline-1 overwrites it with ES ingest time", diff --git a/salt/elasticsearch/ssl.sls b/salt/elasticsearch/ssl.sls index a2d327830..7d54dfd56 100644 --- a/salt/elasticsearch/ssl.sls +++ b/salt/elasticsearch/ssl.sls @@ -38,10 +38,6 @@ elasticsearch_crt: - retry: attempts: 5 interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/elasticsearch.key -in /etc/pki/elasticsearch.crt -export -out /etc/pki/elasticsearch.p12 -nodes -passout pass:" - - onchanges: - - x509: /etc/pki/elasticsearch.key elastickeyperms: file.managed: @@ -50,13 +46,6 @@ elastickeyperms: - mode: 640 - group: 930 -elasticp12perms: - file.managed: - - replace: False - - name: /etc/pki/elasticsearch.p12 - - mode: 640 - - group: 930 - {% else %} {{sls}}_state_not_allowed: diff --git a/salt/elasticsearch/templates/component/so/detection-mappings.json b/salt/elasticsearch/templates/component/so/detection-mappings.json index 4dd5b45e7..326a8a712 100644 --- a/salt/elasticsearch/templates/component/so/detection-mappings.json +++ b/salt/elasticsearch/templates/component/so/detection-mappings.json @@ -154,6 +154,20 @@ } } } + }, + "runtime": { + "so_detection.sigmaKind": { + "type": "keyword", + "script": { + "source": "if (doc['so_detection.language'].size() == 0 || doc['so_detection.language'].value != 'sigma') { return; } def d = params._source.so_detection; if (d == null || d.content == null) { return; } String c = d.content; String NL = String.valueOf((char) 10); emit(c.startsWith('correlation:') || c.contains(NL + 'correlation:') ? 'correlation' : 'single');" + } + }, + "so_detection.sigmaCorrelationType": { + "type": "keyword", + "script": { + "source": "if (doc['so_detection.language'].size() == 0 || doc['so_detection.language'].value != 'sigma') { return; } def d = params._source.so_detection; if (d == null || d.content == null) { return; } String c = d.content; String NL = String.valueOf((char) 10); int i = c.startsWith('correlation:') ? 0 : c.indexOf(NL + 'correlation:'); if (i < 0) { return; } i = c.indexOf(NL, i + 1); while (i >= 0 && i + 1 < c.length()) { int e = c.indexOf(NL, i + 1); String line = e < 0 ? c.substring(i + 1) : c.substring(i + 1, e); if (line.length() > 0 && !Character.isWhitespace(line.charAt(0)) && line.charAt(0) != (char) 35) { return; } String t = line.trim(); if (t.startsWith('type:')) { String v = t.substring(5).trim(); int h = v.indexOf(' ' + String.valueOf((char) 35)); if (h >= 0) { v = v.substring(0, h).trim(); } if (v.length() > 1 && (v.charAt(0) == (char) 39 || v.charAt(0) == (char) 34)) { v = v.substring(1, v.length() - 1); } emit(v); return; } i = e; }" + } + } } } }, diff --git a/salt/elasticsearch/templates/component/so/detections-alerts-mappings.json b/salt/elasticsearch/templates/component/so/detections-alerts-mappings.json new file mode 100644 index 000000000..5a2abfb7f --- /dev/null +++ b/salt/elasticsearch/templates/component/so/detections-alerts-mappings.json @@ -0,0 +1,149 @@ +{ + "template": { + "mappings": { + "properties": { + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "sigma_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "rule": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "ignore_above": 1024, + "type": "keyword" + }, + "correlation": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "severity": { + "type": "long" + }, + "severity_label": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "reason": { + "type": "match_only_text", + "fields": { + "keyword": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "type": "keyword", + "index": false, + "doc_values": false + } + } + }, + "event_data": { + "properties": { + "@timestamp": { + "type": "date" + }, + "window_start": { + "type": "date" + }, + "event_count": { + "type": "long" + }, + "value_count": { + "type": "long" + }, + "event_type_count": { + "type": "long" + }, + "value_sum": { + "type": "double" + }, + "value_avg": { + "type": "double" + }, + "value_percentile": { + "type": "double" + }, + "value_median": { + "type": "double" + } + } + }, + "labels": { + "properties": { + "correlation_group_by": { + "ignore_above": 1024, + "type": "keyword" + }, + "correlation_group": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + }, + "hosts": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "properties": { + "message": { + "type": "match_only_text" + } + } + } + } + } + }, + "_meta": { + "description": "Fields written by the ElastAlert SecurityOnionESAlerter to logs-detections.alerts-so" + } +} diff --git a/salt/elasticsearch/tools/sbin_jinja/so-catrust b/salt/elasticsearch/tools/sbin_jinja/so-catrust deleted file mode 100644 index 14f9e5ca1..000000000 --- a/salt/elasticsearch/tools/sbin_jinja/so-catrust +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -. /usr/sbin/so-common -get_elastic_agent_vars - -# Exit on errors, since all lines must succeed -set -e - -# Check to see if we have extracted the ca cert. -if [ ! -f /opt/so/saltstack/local/salt/elasticsearch/cacerts ]; then - docker run -v /etc/pki/ca.crt:/etc/ssl/ca.crt --name so-elasticsearchca --user root --entrypoint jdk/bin/keytool {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:$ELASTIC_AGENT_TARBALL_VERSION -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -alias SOSCA -import -file /etc/ssl/ca.crt -storepass changeit -noprompt - # Make sure symbolic links are followed when copying from container - docker cp -L so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts - docker cp -L so-elasticsearchca:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem - docker rm so-elasticsearchca - echo "" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem - echo "sosca" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem - cat /etc/pki/ca.crt >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem -else - exit 0 -fi diff --git a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load index 9b748ce59..b2f277669 100755 --- a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load +++ b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load @@ -7,11 +7,17 @@ . /usr/sbin/so-common MAX_JOBS=${MAX_ILM_JOBS:-10} +ILM_STATEFILE=/opt/so/state/esilm.txt +rm -f "$ILM_STATEFILE" +check_elasticsearch_responsive + +ILM_TMP_DIR=$(mktemp -d) +trap 'rm -rf "$ILM_TMP_DIR"' EXIT # Lock used to serialize block writes so concurrent jobs never interleave their output. -ILM_OUTPUT_LOCK=$(mktemp) -ILM_FAIL_FILE=$(mktemp) -trap 'rm -f "$ILM_OUTPUT_LOCK" "$ILM_FAIL_FILE"' EXIT +ILM_OUTPUT_LOCK="$ILM_TMP_DIR/output.lock" +ILM_FAIL_FILE="$ILM_TMP_DIR/failed" +touch "$ILM_FAIL_FILE" # Policies are loaded concurrently (up to MAX_JOBS at a time) for speed. Each policy's block is # printed the moment its curl returns, so output appears in COMPLETION ORDER, not the order @@ -20,13 +26,30 @@ echo "Loading ILM policies concurrently; output below appears in completion orde echo put_policy() { - local desc="$1" policyname="$2" data="$3" result rc=0 - if ! result=$(curl -K /opt/so/conf/elasticsearch/curl.config -s -k -L --fail \ - -X PUT "https://localhost:9200/_ilm/policy/${policyname}" \ - -H 'Content-Type: application/json' -d"${data}" 2>&1); then - rc=1 - elif ! jq -e '.acknowledged == true' <<<"$result" >/dev/null 2>&1; then - rc=1 + local desc="$1" policyname="$2" data="$3" rc=1 attempt out http_code body result reason tmpdata + tmpdata=$(mktemp "$ILM_TMP_DIR/${policyname}.XXXXXX.json") + printf '%s' "$data" >"$tmpdata" + + for attempt in 1 2 3; do + out=$(so-elasticsearch-query "_ilm/policy/${policyname}" -d@"${tmpdata}" -XPUT -w '\n%{http_code}' 2>/dev/null) + http_code=${out##*$'\n'} body=${out%$'\n'*} + + if [[ "$http_code" == 200 ]] && jq -e '.acknowledged == true' <<<"$body" >/dev/null 2>&1; then + rc=0 + break + fi + # 429 = ES rejected/throttled (may succeed later); other 4xx will not + [[ "$http_code" == 4?? && "$http_code" != 429 ]] && break + (( attempt < 3 )) && sleep 3 + done + + if (( rc == 0 )); then + result='{"acknowledged":true}' + else + result=${body:-"HTTP ${http_code:-000}"} + # flatten tabs/newlines so the TAB fail-file stays one record + reason=$(jq -r '(if (.error|type) == "object" then (.error.reason // .error.type) elif (.error|type) == "string" then .error else empty end) // empty | tostring | gsub("[\t\r\n]+"; " ")' <<<"$body" 2>/dev/null) + reason="HTTP ${http_code:-000}${reason:+: ${reason}}" fi # curl above ran in parallel; serialize just this block write so concurrent jobs never interleave. @@ -34,7 +57,7 @@ put_policy() { flock 200 printf 'Setting up %s policy...\n%s\n\n' "${desc}" "${result}" if (( rc != 0 )); then - printf '%s\n' "${policyname}" >>"$ILM_FAIL_FILE" + printf '%s\t%s\n' "${policyname}" "${reason}" >>"$ILM_FAIL_FILE" fi } 200>>"${ILM_OUTPUT_LOCK}" @@ -82,10 +105,15 @@ wait || true if [[ -s "$ILM_FAIL_FILE" ]]; then echo "ERROR: Failed to load ILM policy(s):" - while read -r POLICY; do - echo " - $POLICY" + while IFS=$'\t' read -r POLICY REASON; do + if [[ -n "$REASON" ]]; then + echo " - ${POLICY}: ${REASON}" + else + echo " - ${POLICY}" + fi done < "$ILM_FAIL_FILE" exit 1 else echo "Successfully loaded all ILM policies." + touch "$ILM_STATEFILE" fi diff --git a/salt/hydra/enabled.sls b/salt/hydra/enabled.sls index 13fce79cf..cdc8ebe04 100644 --- a/salt/hydra/enabled.sls +++ b/salt/hydra/enabled.sls @@ -13,9 +13,11 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% if 'api' in salt['pillar.get']('features', []) %} include: + - ca.trust - hydra.config - hydra.sostatus @@ -29,6 +31,7 @@ so-hydra: - soauth: - ipv4_address: {{ DOCKERMERGED.containers['so-hydra'].ips['soauth'] }} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/hydra/:/hydra-conf:ro - /opt/so/log/hydra/:/hydra-log:rw - /nsm/hydra/db:/hydra-data:rw @@ -60,6 +63,7 @@ so-hydra: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: hydraconfig - require: - file: hydraconfig diff --git a/salt/idh/enabled.sls b/salt/idh/enabled.sls index 2a02d1f85..95e4976b2 100644 --- a/salt/idh/enabled.sls +++ b/salt/idh/enabled.sls @@ -6,9 +6,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - idh.config - idh.sostatus @@ -20,6 +22,7 @@ so-idh: - detach: True - network_mode: host - binds: + - {{ CATRUST.dir }} - /nsm/idh:/var/tmp:rw - /opt/so/conf/idh/http-skins:/opt/opencanary/http-skins:ro - /opt/so/conf/idh/opencanary.conf:/etc/opencanaryd/opencanary.conf:ro @@ -34,12 +37,13 @@ so-idh: - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKERMERGED.containers['so-idh'].extra_env %} - environment: - {% for XTRAENV in DOCKERMERGED.containers['so-idh'].extra_env %} + - REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt + {% if DOCKERMERGED.containers['so-idh'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-idh'].extra_env %} - {{ XTRAENV }} - {% endfor %} - {% endif %} + {% endfor %} + {% endif %} {% if DOCKERMERGED.containers['so-idh'].ulimits %} - ulimits: {% for ULIMIT in DOCKERMERGED.containers['so-idh'].ulimits %} @@ -47,6 +51,7 @@ so-idh: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: opencanary_config - require: - file: opencanary_config diff --git a/salt/influxdb/enabled.sls b/salt/influxdb/enabled.sls index 617a56e1e..1ca23e833 100644 --- a/salt/influxdb/enabled.sls +++ b/salt/influxdb/enabled.sls @@ -6,11 +6,13 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% set PASSWORD = salt['pillar.get']('secrets:influx_pass') %} {% set TOKEN = salt['pillar.get']('influxdb:token') %} include: + - ca.trust - influxdb.ssl - influxdb.config - influxdb.sostatus @@ -38,6 +40,7 @@ so-influxdb: {% endfor %} {% endif %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/log/influxdb/:/log:rw - /opt/so/conf/influxdb/config.yaml:/conf/config.yaml:ro - /opt/so/conf/influxdb/etc:/etc/influxdb2:rw @@ -66,6 +69,7 @@ so-influxdb: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: influxdbconf - x509: influxdb_key - x509: influxdb_crt diff --git a/salt/kafka/enabled.sls b/salt/kafka/enabled.sls index 85e05ae4f..108187484 100644 --- a/salt/kafka/enabled.sls +++ b/salt/kafka/enabled.sls @@ -12,12 +12,14 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% set KAFKANODES = salt['pillar.get']('kafka:nodes') %} {% set KAFKA_EXTERNAL_ACCESS = salt['pillar.get']('kafka:config:external_access:enabled', default=False) %} {% if 'gmd' in salt['pillar.get']('features', []) %} include: + - ca.trust - kafka.ca - kafka.config - kafka.ssl @@ -51,6 +53,7 @@ so-kafka: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.java }}:/opt/java/openjdk/lib/security/cacerts:ro - /etc/pki/kafka.p12:/etc/pki/kafka.p12:ro - /opt/so/conf/kafka/kafka-truststore.jks:/etc/pki/kafka-truststore.jks:ro - /nsm/kafka/data/:/nsm/kafka/data/:rw @@ -61,6 +64,11 @@ so-kafka: {% if KAFKA_EXTERNAL_ACCESS %} - /opt/so/conf/kafka/kafka_server_jaas.conf:/opt/kafka/config/kafka_server_jaas.conf:ro {% endif %} + {% if DOCKERMERGED.containers['so-kafka'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-kafka'].custom_bind_mounts %} + - {{ BIND }} + {% endfor %} + {% endif %} {% if DOCKERMERGED.containers['so-kafka'].ulimits %} - ulimits: {% for ULIMIT in DOCKERMERGED.containers['so-kafka'].ulimits %} @@ -68,6 +76,7 @@ so-kafka: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract {% for sc in ['server', 'client'] %} - file: kafka_kraft_{{sc}}_properties {% endfor %} diff --git a/salt/kibana/defaults.yaml b/salt/kibana/defaults.yaml index a4b141e7d..01abc24c4 100644 --- a/salt/kibana/defaults.yaml +++ b/salt/kibana/defaults.yaml @@ -22,7 +22,7 @@ kibana: - default - file migrations: - discardCorruptObjects: "9.4.5" + discardCorruptObjects: "9.4.8" telemetry: enabled: False xpack: diff --git a/salt/kibana/enabled.sls b/salt/kibana/enabled.sls index 0e986dbc2..9852242fe 100644 --- a/salt/kibana/enabled.sls +++ b/salt/kibana/enabled.sls @@ -8,8 +8,10 @@ {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - kibana.config - kibana.sostatus @@ -27,6 +29,7 @@ so-kibana: - ELASTICSEARCH_HOST={{ GLOBALS.manager }} - ELASTICSEARCH_PORT=9200 - MANAGER={{ GLOBALS.manager }} + - NODE_OPTIONS=--use-openssl-ca {% if DOCKERMERGED.containers['so-kibana'].extra_env %} {% for XTRAENV in DOCKERMERGED.containers['so-kibana'].extra_env %} - {{ XTRAENV }} @@ -40,6 +43,7 @@ so-kibana: {% endfor %} {% endif %} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/kibana/etc:/usr/share/kibana/config:rw - /opt/so/log/kibana:/var/log/kibana:rw - /opt/so/conf/kibana/customdashboards:/usr/share/kibana/custdashboards:ro @@ -60,6 +64,7 @@ so-kibana: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: kibanaconfig wait_for_so-kibana: diff --git a/salt/kratos/enabled.sls b/salt/kratos/enabled.sls index 38a710cfc..046f890ab 100644 --- a/salt/kratos/enabled.sls +++ b/salt/kratos/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - kratos.config - kratos.sostatus @@ -22,6 +24,7 @@ so-kratos: - soauth: - ipv4_address: {{ DOCKERMERGED.containers['so-kratos'].ips['soauth'] }} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/kratos/:/kratos-conf:ro - /opt/so/log/kratos/:/kratos-log:rw - /nsm/kratos/db:/kratos-data:rw @@ -53,6 +56,7 @@ so-kratos: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: kratosschema - file: kratosconfig - require: diff --git a/salt/logstash/enabled.sls b/salt/logstash/enabled.sls index 003cabf21..0b3d8447a 100644 --- a/salt/logstash/enabled.sls +++ b/salt/logstash/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'logstash/map.jinja' import LOGSTASH_MERGED %} {% from 'logstash/map.jinja' import LOGSTASH_NODES %} @@ -13,9 +14,6 @@ include: - ca -{% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - - elasticsearch.ca -{% endif %} {# Kafka ca runs on nodes that can run logstash for Kafka input / output. Only when Kafka is global pipeline #} {% if GLOBALS.role in ['so-searchnode', 'so-manager', 'so-managerhype', 'so-managersearch', 'so-receiver', 'so-standalone'] and GLOBALS.pipeline == 'KAFKA' %} - kafka.ca @@ -58,6 +56,8 @@ so-logstash: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.dir }} + - {{ CATRUST.java }}:/usr/share/logstash/jdk/lib/security/cacerts:ro - /opt/so/conf/elasticsearch/templates/:/templates/:ro - /opt/so/conf/logstash/etc/:/usr/share/logstash/config/:ro - /opt/so/conf/logstash/pipelines:/usr/share/logstash/pipelines:ro @@ -78,10 +78,6 @@ so-logstash: - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro {% endif %} {% endif %} - {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - - /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro - - /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro - {% endif %} {% if GLOBALS.pipeline == "KAFKA" and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} - /etc/pki/kafka-logstash.p12:/usr/share/logstash/kafka-logstash.p12:ro - /opt/so/conf/kafka/kafka-truststore.jks:/etc/pki/kafka-truststore.jks:ro @@ -104,14 +100,11 @@ so-logstash: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: lsetcsync - file: lslog4j2 - file: lspipelinesyml - file: trusttheca - {% if GLOBALS.is_manager %} - - file: elasticsearch_cacerts - - file: elasticsearch_capems - {% endif %} {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} - x509: etc_elasticfleet_logstash_crt - x509: etc_elasticfleet_logstash_key @@ -133,10 +126,6 @@ so-logstash: {% endif %} - require: - file: trusttheca - {% if GLOBALS.is_manager %} - - file: elasticsearch_cacerts - - file: elasticsearch_capems - {% endif %} {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} - x509: etc_elasticfleet_logstash_crt - x509: etc_elasticfleet_logstash_key diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 20c2528dc..ba27ca004 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -121,9 +121,6 @@ check_err() { 161) echo 'Required intermediate Elasticsearch upgrade not complete' ;; - 162) - echo 'One or more Elastic Agent nodes do not support the x86-64-v3 CPU instruction set' - ;; 170) echo "Intermediate upgrade completed successfully to $next_step_so_version, but next soup to Security Onion $originally_requested_so_version could not be started automatically." echo "Start soup again manually to continue the upgrade to Security Onion $originally_requested_so_version." @@ -351,83 +348,6 @@ check_cluster_health() { exit 0 } -no_soup_for_you() { - echo "" - echo "No soup for you!" - exit 162 -} - -check_cpu_compatibility() { - # Roles running a container built from the so-elastic-agent image; mirrors the - # elasticagent and elasticfleet entries in salt/reactor/pillar_push_map.yaml. - local cpu_target='G@role:so-heavynode or G@role:so-eval or G@role:so-fleet or G@role:so-import or G@role:so-manager or G@role:so-managerhype or G@role:so-managersearch or G@role:so-standalone' - local expected_nodes cpu_results node result confirm - local -a unsupported=() offline=() - - echo "Checking that Elastic Agent nodes support the x86-64-v3 CPU instruction set now required by Elastic." - - if [[ "$SKIP_CPU_CHECK" == "true" ]]; then - printf "\nSkipping the x86-64-v3 CPU check because --skip-cpu-check was specified.\n\n" - return - fi - - # Nodes that never answer are absent from the results, so diff against who should have. - expected_nodes=$(salt -C "$cpu_target" --preview-target --out=json 2>/dev/null | jq -r '.[]?') || true - if [[ -z "$expected_nodes" ]]; then - printf "\nCould not determine which nodes run the Elastic Agent, so the x86-64-v3 CPU check cannot run.\n" - no_soup_for_you - fi - - cpu_results=$(salt -t 30 -C "$cpu_target" cmd.run "/lib64/ld-linux-x86-64.so.2 --help | grep x86-64-v3" --out=json 2>/dev/null) || true - - while IFS= read -r node; do - [[ -z "$node" ]] && continue - result=$(jq -r --arg node "$node" '.[$node] // empty' <<< "$cpu_results" 2>/dev/null) - if [[ -z "$result" || "$result" == *"did not return"* ]]; then - offline+=("$node") - elif [[ "$result" != *"x86-64-v3 (supported"* ]]; then - # glibc appends "(supported, searched)" only when supported; the open paren keeps - # this from matching a future "(unsupported". - unsupported+=("$node") - fi - done <<< "$expected_nodes" - - if [[ ${#unsupported[@]} -eq 0 && ${#offline[@]} -eq 0 ]]; then - printf "\nAll Elastic Agent nodes support x86-64-v3. We can proceed with SOUP.\n\n" - return - fi - - echo "" - if [[ ${#unsupported[@]} -gt 0 ]]; then - echo "The following node(s) do NOT support the x86-64-v3 CPU instruction set:" - printf ' %s\n' "${unsupported[@]}" - echo "" - echo "Upstream Elastic now builds its binaries for x86-64-v3, so these nodes can no" - echo "longer run Elastic. Upgrading them WILL BREAK them." - echo "" - fi - if [[ ${#offline[@]} -gt 0 ]]; then - echo "The following node(s) did not respond and could not be checked:" - printf ' %s\n' "${offline[@]}" - echo "" - echo "These nodes are offline, so we cannot confirm they support x86-64-v3, which" - echo "upstream Elastic now requires." - echo "" - fi - - if [[ -n $UNATTENDED ]]; then - echo "Unattended mode cannot prompt for an override. Re-run soup interactively, or pass --skip-cpu-check to bypass this check." - no_soup_for_you - fi - - read -rp "Type 'override' to continue anyway, or press Enter to exit: " confirm - if [[ "${confirm,,}" == "override" ]]; then - printf "\nOverride accepted. Continuing at your own risk.\n\n" - else - no_soup_for_you - fi -} - check_fleet_server() { echo "Checking that Elastic Fleet Server is responding." # Modeled on the wait_for_so-elastic-fleet state check in elasticfleet/enabled.sls, @@ -1131,9 +1051,6 @@ post_to_3.2.0() { ### 3.3.0 Scripts ### up_to_3.3.0() { - # download 9.4.5 elastic agent packages - determine_elastic_agent_upgrade - # remove existing (patched) elasticsearch index template to match integration naming change if ! remove_elasticsearch_index_template "so-logs-sentinel_one_cloud_funnel.login" "sentinel_one_cloud_funnel.login changed to sentinel_one_cloud_funnel.logins"; then FINAL_MESSAGE_QUEUE+=("WARNING: Unable to automatically remove the so-logs-sentinel_one_cloud_funnel.login index template. This step can be performed manually using the following command:") @@ -1165,11 +1082,7 @@ telegraf_repair() { post_to_3.3.0() { # Recollate again since some internal DBs were excluded during 3.2.0 soup recollate_postgres - - # Generate 9.4.5 elastic agent installers - echo "Regenerating Elastic Agent Installers" - /sbin/so-elastic-agent-gen-installers - + telegraf_repair set_postversion 3.3.0 @@ -1178,6 +1091,9 @@ post_to_3.3.0() { ### 3.4.0 Scripts ### up_to_3.4.0() { + # download 9.4.8 elastic agent packages + determine_elastic_agent_upgrade + set_soauth_range echo "Removing so-kratos, so-hydra and so-soc so they are recreated on the soauth network." @@ -1255,12 +1171,35 @@ valid_soauth_range() { } post_to_3.4.0() { + # Generate 9.4.8 elastic agent installers + echo "Regenerating Elastic Agent Installers" + /sbin/so-elastic-agent-gen-installers + for idx in "metrics-logstash.node-default" "metrics-logstash.stack_monitoring.node-default"; do rollover_index "$idx" done + add_detection_runtime_fields + + remove_frozen_ca_bundles + set_postversion 3.4.0 } + +remove_frozen_ca_bundles() { + rm -f /opt/so/saltstack/local/salt/elasticsearch/cacerts /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem >> $SOUP_LOG 2>&1 +} + +add_detection_runtime_fields() { + local template=$DEFAULT_SALT_DIR/salt/elasticsearch/templates/component/so/detection-mappings.json + local runtime + + runtime=$(jq -c '{runtime: .template.mappings.runtime}' "$template") + if ! so-elasticsearch-query so-detection/_mapping -XPUT -d "$runtime" --retry 3 --retry-delay 5 --fail >> $SOUP_LOG 2>&1; then + FINAL_MESSAGE_QUEUE+=("WARNING: Unable to add the Sigma search fields to the so-detection index. Searches on so_detection.sigmaKind will match nothing until they are added:") + FINAL_MESSAGE_QUEUE+=(" - sudo so-elasticsearch-query so-detection/_mapping -XPUT -d \"\$(jq -c '{runtime: .template.mappings.runtime}' $template)\"") + fi +} ### 3.4.0 End ### @@ -1535,9 +1474,10 @@ verify_es_version_compatibility() { ["8.18.4"]="8.18.6 8.18.8 9.0.8" ["8.18.6"]="8.18.8 9.0.8" ["8.18.8"]="9.0.8" - ["9.0.8"]="9.3.3 9.3.7 9.4.5" - ["9.3.3"]="9.3.7 9.4.5" - ["9.3.7"]="9.4.5" + ["9.0.8"]="9.3.3 9.3.7 9.4.5 9.4.8" + ["9.3.3"]="9.3.7 9.4.5 9.4.8" + ["9.3.7"]="9.4.5 9.4.8" + ["9.4.5"]="9.4.8" ) # Elasticsearch MUST upgrade through these versions @@ -2148,8 +2088,6 @@ main() { echo "Let's see if we need to update Security Onion." upgrade_check - check_cpu_compatibility - upgrade_space echo "Verifying Elasticsearch version compatibility across the grid before upgrading." @@ -2428,17 +2366,6 @@ fi echo "### soup has been served at $(date) ###" } -SKIP_CPU_CHECK=false -declare -a SOUP_ARGS=() -for arg in "$@"; do - if [[ "$arg" == "--skip-cpu-check" ]]; then - SKIP_CPU_CHECK=true - else - SOUP_ARGS+=("$arg") - fi -done -set -- "${SOUP_ARGS[@]}" - while getopts ":b:f:y" opt; do case ${opt} in b ) @@ -2462,7 +2389,7 @@ while getopts ":b:f:y" opt; do ISOLOC="$OPTARG" ;; \? ) - echo "Usage: soup [-b] [-y] [-f ] [--skip-cpu-check]" + echo "Usage: soup [-b] [-y] [-f ]" exit 1 ;; : ) diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index 3fa99eae2..cf3cb1e81 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -6,10 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'nginx/map.jinja' import NGINXMERGED %} include: + - ca.trust - nginx.ssl - nginx.config - nginx.sostatus @@ -47,6 +49,7 @@ so-nginx: {% endfor %} {% endif %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - /opt/so/log/nginx/:/var/log/nginx:rw - /opt/so/tmp/nginx/:/var/lib/nginx:rw @@ -89,6 +92,7 @@ so-nginx: - {{ BINDING }} {% endfor %} - watch: + - cmd: ca_trust_extract - file: nginxconf - file: nginxconfdir {% if GLOBALS.is_manager %} diff --git a/salt/postgres/enabled.sls b/salt/postgres/enabled.sls index fa91d146a..088ad6f54 100644 --- a/salt/postgres/enabled.sls +++ b/salt/postgres/enabled.sls @@ -6,10 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% set SO_POSTGRES_USER = salt['pillar.get']('postgres:auth:users:so_postgres_user:user', 'so_postgres') %} include: + - ca.trust - postgres.auth - postgres.ssl - postgres.config @@ -42,6 +44,7 @@ so-postgres: {% endfor %} {% endif %} - binds: + - {{ CATRUST.dir }} - /opt/so/log/postgres/:/log:rw - /nsm/postgres:/var/lib/postgresql/data:rw - /opt/so/conf/postgres/postgresql.conf:/conf/postgresql.conf:ro @@ -69,6 +72,7 @@ so-postgres: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: postgresconf - file: postgreshba - file: postgresinitdb diff --git a/salt/redis/enabled.sls b/salt/redis/enabled.sls index 1c9d1afa0..57bbe279c 100644 --- a/salt/redis/enabled.sls +++ b/salt/redis/enabled.sls @@ -7,6 +7,7 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: - ca @@ -28,6 +29,7 @@ so-redis: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/log/redis:/var/log/redis:rw - /opt/so/conf/redis/etc/redis.conf:/usr/local/etc/redis/redis.conf:ro - /opt/so/conf/redis/working:/redis:rw @@ -60,6 +62,7 @@ so-redis: {% endif %} - entrypoint: "redis-server /usr/local/etc/redis/redis.conf" - watch: + - cmd: ca_trust_extract - file: trusttheca - x509: redis_crt - x509: redis_key diff --git a/salt/registry/enabled.sls b/salt/registry/enabled.sls index b2bfbc56d..9b69a380a 100644 --- a/salt/registry/enabled.sls +++ b/salt/registry/enabled.sls @@ -6,9 +6,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - registry.ssl - registry.config - registry.sostatus @@ -29,6 +31,7 @@ so-dockerregistry: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/conf/docker-registry/etc/config.yml:/etc/distribution/config.yml:ro - /opt/so/conf/docker-registry:/var/lib/registry:rw - /nsm/docker-registry/docker:/var/lib/registry/docker:rw @@ -63,6 +66,7 @@ so-dockerregistry: attempts: 5 interval: 30 - watch: + - cmd: ca_trust_extract - x509: registry_crt - x509: registry_key - require: diff --git a/salt/salt/module_packages/docker/certifi-2024.7.4-py3-none-any.whl b/salt/salt/module_packages/docker/certifi-2024.7.4-py3-none-any.whl deleted file mode 100644 index 9e412a2d9..000000000 Binary files a/salt/salt/module_packages/docker/certifi-2024.7.4-py3-none-any.whl and /dev/null differ diff --git a/salt/salt/module_packages/docker/certifi-2026.10.19-py3-none-any.whl b/salt/salt/module_packages/docker/certifi-2026.10.19-py3-none-any.whl new file mode 100644 index 000000000..c9cedc096 Binary files /dev/null and b/salt/salt/module_packages/docker/certifi-2026.10.19-py3-none-any.whl differ diff --git a/salt/salt/module_packages/onedir/certifi-2026.10.19-py3-none-any.whl b/salt/salt/module_packages/onedir/certifi-2026.10.19-py3-none-any.whl new file mode 100644 index 000000000..c9cedc096 Binary files /dev/null and b/salt/salt/module_packages/onedir/certifi-2026.10.19-py3-none-any.whl differ diff --git a/salt/salt/module_packages/onedir/pip-26.2.2-py3-none-any.whl b/salt/salt/module_packages/onedir/pip-26.2.2-py3-none-any.whl new file mode 100644 index 000000000..d884a0ad8 Binary files /dev/null and b/salt/salt/module_packages/onedir/pip-26.2.2-py3-none-any.whl differ diff --git a/salt/salt/module_packages/onedir/relenv-0.22.27-py3-none-any.whl b/salt/salt/module_packages/onedir/relenv-0.22.27-py3-none-any.whl new file mode 100644 index 000000000..f74222f97 Binary files /dev/null and b/salt/salt/module_packages/onedir/relenv-0.22.27-py3-none-any.whl differ diff --git a/salt/salt/python_modules.sls b/salt/salt/python_modules.sls index d6c05a892..cf6d0fde7 100644 --- a/salt/salt/python_modules.sls +++ b/salt/salt/python_modules.sls @@ -3,6 +3,31 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +{% set ONEDIR_PACKAGES = {'relenv': '0.22.27', 'pip': '26.2.2', 'certifi': '2026.10.19'} %} + +{% if grains.saltversion == '3006.19' %} +onedir_package: + file.recurse: + - name: /opt/so/conf/salt/module_packages/onedir + - source: salt://salt/module_packages/onedir + - clean: True + - makedirs: True + +# Backport of salt 3006.29 (PR 70466): certifi 2026.10.19 and pip 26.2.2 drop the compromised +# eMudhra/emSign root. relenv must move with pip: 0.22.2's runtime wrapper hardcodes pre-26.2 pip +# install() signatures, so a lone pip upgrade breaks every later pip run in the onedir. Installing +# all three in one invocation under the stock pip avoids ever being in that state. +onedir_python_module_install: + cmd.run: + - name: /opt/saltstack/salt/bin/python3.10 -m pip install --no-index --find-links=/opt/so/conf/salt/module_packages/onedir/ --upgrade --root-user-action=ignore {% for pkg, ver in ONEDIR_PACKAGES.items() %}{{ pkg }}=={{ ver }} {% endfor %} + - unless: /opt/saltstack/salt/bin/python3.10 -c 'import {{ ONEDIR_PACKAGES.keys() | join(", ") }}; assert {% for pkg, ver in ONEDIR_PACKAGES.items() %}{{ pkg }}.__version__ == "{{ ver }}"{% if not loop.last %} and {% endif %}{% endfor %}' + - require: + - file: onedir_package + - require_in: + - cmd: docker_python_module_install + - failhard: True +{% endif %} + docker_module_package: file.recurse: - name: /opt/so/conf/salt/module_packages/docker diff --git a/salt/sensoroni/enabled.sls b/salt/sensoroni/enabled.sls index db4b91dd0..0c8086832 100644 --- a/salt/sensoroni/enabled.sls +++ b/salt/sensoroni/enabled.sls @@ -4,10 +4,12 @@ # Elastic License 2.0. {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - sensoroni.config - sensoroni.sostatus @@ -17,6 +19,7 @@ so-sensoroni: - restart_policy: unless-stopped - network_mode: host - binds: + - {{ CATRUST.dir }} - /nsm/import:/nsm/import:rw - /nsm/pcapout:/nsm/pcapout:rw - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro @@ -48,6 +51,7 @@ so-sensoroni: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: /opt/so/conf/sensoroni/sensoroni.json - require: - file: sensoroniagentconf diff --git a/salt/sensoroni/files/analyzers/elasticsearch/requirements.txt b/salt/sensoroni/files/analyzers/elasticsearch/requirements.txt index 43b300e1d..6f7838136 100644 --- a/salt/sensoroni/files/analyzers/elasticsearch/requirements.txt +++ b/salt/sensoroni/files/analyzers/elasticsearch/requirements.txt @@ -1,3 +1,5 @@ requests>=2.31.0 pyyaml>=6.0 -urllib3>=2.1.0 \ No newline at end of file +urllib3>=2.1.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/requirements.txt b/salt/sensoroni/files/analyzers/emailrep/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/emailrep/requirements.txt +++ b/salt/sensoroni/files/analyzers/emailrep/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/requirements.txt b/salt/sensoroni/files/analyzers/greynoise/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/greynoise/requirements.txt +++ b/salt/sensoroni/files/analyzers/greynoise/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/requirements.txt b/salt/sensoroni/files/analyzers/localfile/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/localfile/requirements.txt +++ b/salt/sensoroni/files/analyzers/localfile/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/requirements.txt b/salt/sensoroni/files/analyzers/malwarebazaar/requirements.txt index 925ada01e..72d53feec 100644 --- a/salt/sensoroni/files/analyzers/malwarebazaar/requirements.txt +++ b/salt/sensoroni/files/analyzers/malwarebazaar/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/requirements.txt b/salt/sensoroni/files/analyzers/malwarehashregistry/requirements.txt index a5a02f4fa..13f86c481 100644 --- a/salt/sensoroni/files/analyzers/malwarehashregistry/requirements.txt +++ b/salt/sensoroni/files/analyzers/malwarehashregistry/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 python-whois>=0.9.5 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl deleted file mode 100644 index b9a14e1bf..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl new file mode 100644 index 000000000..fbb00daa5 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/tzdata-2026.6-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/tzdata-2026.6-py2.py3-none-any.whl new file mode 100644 index 000000000..345e0b9ec Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/tzdata-2026.6-py2.py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/requirements.txt b/salt/sensoroni/files/analyzers/otx/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/otx/requirements.txt +++ b/salt/sensoroni/files/analyzers/otx/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/requirements.txt b/salt/sensoroni/files/analyzers/pulsedive/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/pulsedive/requirements.txt +++ b/salt/sensoroni/files/analyzers/pulsedive/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/requirements.txt b/salt/sensoroni/files/analyzers/spamhaus/requirements.txt index 9ec0d5539..bf411ea52 100644 --- a/salt/sensoroni/files/analyzers/spamhaus/requirements.txt +++ b/salt/sensoroni/files/analyzers/spamhaus/requirements.txt @@ -1,2 +1,4 @@ dnspython>=2.2.1 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/spamhaus/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl deleted file mode 100644 index d618ba05d..000000000 Binary files a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.9.1-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.9.1-py3-none-any.whl new file mode 100644 index 000000000..51e303c1a Binary files /dev/null and b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.9.1-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/spamhaus/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/requirements.txt b/salt/sensoroni/files/analyzers/sublime/requirements.txt index a8980057f..8c7d36de5 100644 --- a/salt/sensoroni/files/analyzers/sublime/requirements.txt +++ b/salt/sensoroni/files/analyzers/sublime/requirements.txt @@ -1,2 +1,4 @@ requests>=2.27.1 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/requirements.txt b/salt/sensoroni/files/analyzers/threatfox/requirements.txt index 925ada01e..72d53feec 100644 --- a/salt/sensoroni/files/analyzers/threatfox/requirements.txt +++ b/salt/sensoroni/files/analyzers/threatfox/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/requirements.txt b/salt/sensoroni/files/analyzers/urlhaus/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/urlhaus/requirements.txt +++ b/salt/sensoroni/files/analyzers/urlhaus/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/requirements.txt b/salt/sensoroni/files/analyzers/urlscan/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/urlscan/requirements.txt +++ b/salt/sensoroni/files/analyzers/urlscan/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/requirements.txt b/salt/sensoroni/files/analyzers/virustotal/requirements.txt index c7ff13467..4097dcdab 100644 --- a/salt/sensoroni/files/analyzers/virustotal/requirements.txt +++ b/salt/sensoroni/files/analyzers/virustotal/requirements.txt @@ -1,2 +1,4 @@ requests>=2.31.0 pyyaml>=6.0 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl deleted file mode 100644 index 9d7fbf09d..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 06be5ddd0..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl deleted file mode 100644 index 28f2c109e..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.20-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.20-py3-none-any.whl new file mode 100644 index 000000000..34af34e71 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.20-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.32.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.32.5-py3-none-any.whl deleted file mode 100644 index 58c3d6a25..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.32.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.34.2-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.34.2-py3-none-any.whl new file mode 100644 index 000000000..fb4b8a784 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/requests-2.34.2-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl deleted file mode 100644 index 69e9ea57b..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d2da97492 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/requirements.txt b/salt/sensoroni/files/analyzers/whoislookup/requirements.txt index e674be96f..764b18638 100755 --- a/salt/sensoroni/files/analyzers/whoislookup/requirements.txt +++ b/salt/sensoroni/files/analyzers/whoislookup/requirements.txt @@ -1,3 +1,5 @@ requests>=2.34.0 whoisit>=4.0.5 -anyio>=4.15.1 \ No newline at end of file +anyio>=4.15.1 +certifi>=2026.10.23 +idna>=3.20 \ No newline at end of file diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.10.23-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.10.23-py3-none-any.whl new file mode 100644 index 000000000..1a5d66ac0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.10.23-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.7.22-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.7.22-py3-none-any.whl deleted file mode 100644 index 7a4afb13a..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.7.22-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index f705206e6..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..7e41beee9 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl deleted file mode 100644 index b9a14e1bf..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-2.9.0.post0-py2.py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl new file mode 100644 index 000000000..fbb00daa5 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/python_dateutil-3.0.0-py2.py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/tzdata-2026.6-py2.py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/tzdata-2026.6-py2.py3-none-any.whl new file mode 100644 index 000000000..345e0b9ec Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/tzdata-2026.6-py2.py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.5-py3-none-any.whl deleted file mode 100644 index fdace3667..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.1.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.1.0-py3-none-any.whl new file mode 100644 index 000000000..af1ebee9a Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.1.0-py3-none-any.whl differ diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 4eeae5579..f643ac09c 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1441,11 +1441,13 @@ soc: rulesFingerprintFile: /opt/sensoroni/fingerprints/sigma.fingerprint stateFilePath: /opt/sensoroni/fingerprints/elastalertengine.state integrityCheckFrequencySeconds: 1200 + partialSyncTimeoutSeconds: 300 + bulkSyncTimeoutSeconds: 1800 rulesRepos: default: - repo: https://github.com/Security-Onion-Solutions/securityonion-resources license: Elastic-2.0 - folder: sigma/stable + folder: sigma community: true rulesetName: securityonion-resources - repo: file:///nsm/rules/custom-local-repos/local-sigma @@ -1455,7 +1457,7 @@ soc: airgap: - repo: file:///nsm/rules/detect-sigma/repos/securityonion-resources license: Elastic-2.0 - folder: sigma/stable + folder: sigma community: true rulesetName: securityonion-resources - repo: file:///nsm/rules/custom-local-repos/local-sigma @@ -1467,6 +1469,8 @@ soc: - emerging_threats_addon useEsql: false esqlCaseInsensitive: true + esqlQueryDelaySeconds: 30 + esqlCorrelationAllowanceSeconds: 600 elastic: hostUrl: remoteHostUrls: [] @@ -1540,8 +1544,9 @@ soc: agentic: false agentMapping: Orchestrator: sonnet@SOAI - Investigator: gemma@SOAI - DetectionEngineer: gemma@SOAI + Investigator: haiku@SOAI + DetectionEngineer: haiku@SOAI + AlertTriage: haiku@SOAI useMemory: false useMemoryScanner: false dontScanBefore: "" @@ -1568,6 +1573,7 @@ soc: tickIntervalSeconds: 60 maxConcurrentItems: 4 maxQueuedItems: 0 + turnTimeoutSeconds: 300 alertTriageEpoch: "2026-09-24T00:00:00Z" tools: filterEventFields: @@ -1696,6 +1702,8 @@ soc: yaraRulesFolder: /opt/sensoroni/yara/rules stateFilePath: /opt/sensoroni/fingerprints/strelkaengine.state integrityCheckFrequencySeconds: 1200 + partialSyncTimeoutSeconds: 300 + bulkSyncTimeoutSeconds: 1800 suricataengine: aiRepoUrl: https://github.com/Security-Onion-Solutions/securityonion-resources aiRepoBranch: generated-summaries-published @@ -1711,6 +1719,8 @@ soc: rulesFingerprintFile: /opt/sensoroni/fingerprints/emerging-all.fingerprint stateFilePath: /opt/sensoroni/fingerprints/suricataengine.state integrityCheckFrequencySeconds: 1200 + partialSyncTimeoutSeconds: 300 + bulkSyncTimeoutSeconds: 1800 ignoredSidRanges: - '1100000-1101000' rulesetSources: @@ -1821,6 +1831,7 @@ soc: cacheExpirationMs: 300000 casesEnabled: true detectionsEnabled: true + allowExternalMarkdownImages: false inactiveTools: ['toolUnused'] exportNodeId: tools: @@ -2522,6 +2533,9 @@ soc: queries: - name: 'Group By Name, Module' query: '* | groupby rule.name event.module* event.severity_label rule.uuid' + - name: 'Group By Assessment, Name' + query: '* | groupby event.so_alerttriage.assessment rule.name event.severity_label rule.uuid' + license: oai - name: 'Group By Sensor, Source IP/Port, Destination IP/Port, Name' query: '* | groupby observer.name source.ip source.port destination.ip destination.port rule.name network.community_id event.severity_label rule.uuid' - name: 'Group By Source IP, Name' @@ -2679,8 +2693,11 @@ soc: query: "so_detection.language:suricata | groupby so_detection.ruleset so_detection.isEnabled | groupby so_detection.category" description: Show all NIDS Detections, which are run with Suricata - name: "Detection Type - Sigma (Elastalert) - All" - query: "so_detection.language:sigma | groupby so_detection.ruleset so_detection.isEnabled | groupby so_detection.category | groupby so_detection.product" + query: "so_detection.language:sigma | groupby so_detection.sigmaKind | groupby so_detection.ruleset so_detection.isEnabled | groupby so_detection.category | groupby so_detection.product" description: Show all Sigma Detections, which are run with Elastalert + - name: "Detection Type - Sigma (Elastalert) - Correlations" + query: "so_detection.sigmaKind:correlation | groupby so_detection.sigmaCorrelationType so_detection.isEnabled | groupby so_detection.ruleset" + description: Show Sigma correlation Detections - name: "Detection Type - YARA (Strelka)" query: "so_detection.language:yara | groupby so_detection.ruleset so_detection.isEnabled" description: Show all YARA detections, which are used by Strelka @@ -2764,7 +2781,7 @@ soc: elastalert: | # This is a Sigma rule template, which uses YAML. Replace all template values with your own values. # The id (UUIDv4) is pregenerated and can safely be used. - # Click "Convert" to convert the Sigma rule to use Security Onion field mappings within an EQL query + # Click "Convert" to convert the Sigma rule to use Security Onion field mappings within a backend query # # Rule Creation Guide: https://github.com/SigmaHQ/sigma/wiki/Rule-Creation-High%E2%80%90Level-Guide # Logsources: https://sigmahq.io/docs/basics/log-sources.html @@ -2794,6 +2811,61 @@ soc: - ' -priv' condition: all of selection_* level: 'high' # info | low | medium | high | critical + elastalert_correlation: | + # Sigma correlation rule; requires ES|QL (useEsql). + # First document: the correlation. Following documents: the rules it references. + # + # This example mirrors the shipped rule c448c9f6 (Repeated SOC Login Failures For One Account). + # Change it before enabling, or you will get two alerts for the same activity. + # To test: log out of SOC and enter a wrong password 5 times for one username. + # + # Types: event_count, value_count, temporal, value_sum, value_avg, value_median, value_percentile. + # Correlation Guide: https://sigmahq.io/docs/meta/correlations.html + # Logsources: https://sigmahq.io/docs/basics/log-sources.html + + title: 'A Short Capitalized Title With Less Than 50 Characters' + id: [publicId] + status: 'experimental' + description: | + Describe what the correlation finds and why relating these events is more + meaningful than any one of them alone. + Example: 5 or more failed SOC logins for one username in 10 minutes. + references: + - 'https://attack.mitre.org/techniques/T1110/001/' + author: '@SecurityOnion' + date: '[today]' + tags: + - attack.credential-access + - attack.t1110.001 + correlation: + type: event_count # count the base rule's events... + rules: + - example_base_rule # ...by the 'name' of the rule below + group-by: + - user.name # ...separately for each username + timespan: 10m # Xs, Xm, Xh + condition: + gte: 5 + falsepositives: + - 'A user entering an old password after a password change' + # Placeholders: %count%, %start%, %end%, %duration%, or any field. + summary: '%count% failed SOC logins for %user.name% in %duration%, from %http.request.headers.x-real-ip%' + level: 'medium' # info | low | medium | high | critical + --- + title: 'SOC Login Failure' + # referenced by 'name' (or 'id') + name: example_base_rule + description: 'One failed SOC login. Put filters here, not in the correlation.' + logsource: + product: kratos + service: application + detection: + selection: + msg: 'Encountered self-service login error.' + condition: selection + # Carried into the alert. + fields: + - http.request.headers.x-real-ip assistant: enabled: false investigationPrompt: Investigate Alert ID {socId} @@ -2813,6 +2885,15 @@ soc: enabled: true adapter: SOAI charsPerTokenEstimate: 4 + - id: haiku + displayName: Claude Haiku + origin: USA + contextLimitSmall: 1000000 + contextLimitLarge: 1000000 + lowBalanceColorAlert: 500000 + enabled: true + adapter: SOAI + charsPerTokenEstimate: 4 - id: gemma displayName: Gemma origin: USA diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index 5c08f8d6b..450aea2cd 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'soc/merged.map.jinja' import DOCKER_EXTRA_HOSTS %} {% from 'soc/merged.map.jinja' import SOCMERGED %} @@ -27,6 +28,7 @@ so-soc: - soauth: - ipv4_address: {{ DOCKERMERGED.containers['so-soc'].ips['soauth'] }} - binds: + - {{ CATRUST.dir }} - /nsm/rules:/nsm/rules:rw - /opt/so/conf/strelka:/opt/sensoroni/yara:rw - /opt/so/conf/sigma:/opt/sensoroni/sigma:rw @@ -62,6 +64,11 @@ so-soc: - /nsm/backup/detections-migration:/nsm/backup/detections-migration:ro - /opt/so/state:/opt/so/state:rw - /etc/pki/tls/certs/intca.crt:/opt/sensoroni/html/so-ca.crt:ro + {% if DOCKERMERGED.containers['so-soc'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-soc'].custom_bind_mounts %} + - {{ BIND }} + {% endfor %} + {% endif %} - extra_hosts: {% for node in DOCKER_EXTRA_HOSTS %} {% for hostname, ip in node.items() %} @@ -90,6 +97,7 @@ so-soc: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: trusttheca - file: /opt/so/conf/soc/* - require: diff --git a/salt/soc/files/soc/sigma_pipelines/sigma_esql_pipeline.yml b/salt/soc/files/soc/sigma_pipelines/sigma_esql_pipeline.yml index 18b3a9f63..bc496ef48 100644 --- a/salt/soc/files/soc/sigma_pipelines/sigma_esql_pipeline.yml +++ b/salt/soc/files/soc/sigma_pipelines/sigma_esql_pipeline.yml @@ -475,3 +475,10 @@ transformations: - type: logsource product: kratos +# SOC reads the mapped group-by columns from this output +postprocessing: + - id: esql_correlation_group_by + type: template + template: '{{ {"query": query, "group_by": rule.group_by} | tojson }}' + rule_conditions: + - type: is_sigma_correlation_rule diff --git a/salt/soc/files/soc/sigma_pipelines/sigma_so_pipeline.yml b/salt/soc/files/soc/sigma_pipelines/sigma_so_pipeline.yml index 89b24f53b..38455a5ed 100644 --- a/salt/soc/files/soc/sigma_pipelines/sigma_so_pipeline.yml +++ b/salt/soc/files/soc/sigma_pipelines/sigma_so_pipeline.yml @@ -14,6 +14,15 @@ transformations: - process.args - related.ip - dns.resolved_ip + # always lowercase: matched exactly with the indexed ':' operator + - id: case_sensitive_categorization_fields + type: set_state + key: case_insensitive_exempt_fields + val: + - tags + - event.category + - event.type + - event.kind # Not every source maps .caseless; EQL/ES|QL already match case-insensitively. - id: caseless_to_parent_fields type: field_name_mapping @@ -118,6 +127,9 @@ transformations: valid_hash_algos: ["MD5", "SHA1", "SHA256", "SHA512", "IMPHASH"] field_prefix: "file" drop_algo_prefix: False + # ecs_windows renamed Hashes; pySigma 1.5+ parses only these + field_to_parse: + - winlog.event_data.Hashes field_name_conditions: - type: include_fields fields: diff --git a/salt/soc/merged.map.jinja b/salt/soc/merged.map.jinja index 452fba0b9..f5d3232a9 100644 --- a/salt/soc/merged.map.jinja +++ b/salt/soc/merged.map.jinja @@ -8,6 +8,7 @@ {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_NODES %} {% from 'manager/map.jinja' import MANAGERMERGED %} {% from 'telegraf/map.jinja' import TELEGRAFMERGED %} +{% from 'elastalert/map.jinja' import ELASTALERTMERGED %} {%- set PG_ENTRY = salt['pillar.get']('telegraf:postgres_creds:' ~ grains.id, {}) %} {%- set PG_USER = PG_ENTRY.get('user', '') %} {%- set PG_PASS = PG_ENTRY.get('pass', '') %} @@ -21,6 +22,43 @@ {% do SOCMERGED.config.server.update({'additionalCA': MANAGERMERGED.additionalCA}) %} {% do SOCMERGED.config.server.update({'insecureSkipVerify': MANAGERMERGED.insecureSkipVerify}) %} +{# pillar.get replaces lists instead of merging them, so combine availableModels by id and alerts queries by name #} +{% set default_models = {} %} +{% for m in SOCDEFAULTS.config.server.client.assistant.availableModels %} +{% do default_models.setdefault(m.id, m) %} +{% endfor %} +{% set merged_models = [] %} +{% set merged_ids = [] %} +{% for m in SOCMERGED.config.server.client.assistant.availableModels or [] %} +{% set model = {} %} +{% do model.update(default_models.get(m.get('id'), {})) %} +{% do model.update(m) %} +{% do merged_models.append(model) %} +{% do merged_ids.append(m.get('id')) %} +{% endfor %} +{% for id, m in default_models.items() if id not in merged_ids %} +{% do merged_models.append(m) %} +{% endfor %} +{% do SOCMERGED.config.server.client.assistant.update({'availableModels': merged_models}) %} + +{% set default_queries = {} %} +{% for q in SOCDEFAULTS.config.server.client.alerts.queries %} +{% do default_queries.setdefault(q.name, q) %} +{% endfor %} +{% set merged_queries = [] %} +{% set merged_names = [] %} +{% for q in SOCMERGED.config.server.client.alerts.queries or [] %} +{% set query = {} %} +{% do query.update(default_queries.get(q.get('name'), {})) %} +{% do query.update(q) %} +{% do merged_queries.append(query) %} +{% do merged_names.append(q.get('name')) %} +{% endfor %} +{% for name, q in default_queries.items() if name not in merged_names %} +{% do merged_queries.append(q) %} +{% endfor %} +{% do SOCMERGED.config.server.client.alerts.update({'queries': merged_queries}) %} + {% if not SOCMERGED.config.server.modules.postgres.host %} {% do SOCMERGED.config.server.modules.postgres.update({'host': GLOBALS.manager}) %} {% endif %} @@ -63,6 +101,10 @@ {% do SOCMERGED.config.server.modules.elastalertengine.update({'enabledSigmaRules': SOCMERGED.config.server.modules.elastalertengine.enabledSigmaRules.default}) %} {% endif %} +{# correlation schedules follow ElastAlert's run_every #} +{% set run_every = ELASTALERTMERGED.config.run_every %} +{% do SOCMERGED.config.server.modules.elastalertengine.update({'elastAlertRunEverySeconds': run_every.get('minutes', 0) * 60 + run_every.get('seconds', 0)}) %} + {# set elastalertengine.rulesRepos, strelkaengine.rulesRepos, and suricataengine.rulesetSources based on airgap or not #} {% if GLOBALS.airgap %} {% do SOCMERGED.config.server.modules.elastalertengine.update({'rulesRepos': SOCMERGED.config.server.modules.elastalertengine.rulesRepos.airgap}) %} @@ -80,6 +122,12 @@ {% do SOCMERGED.config.server.update({'airgapEnabled': false}) %} {% endif %} +{# correlation authoring requires ES|QL #} +{% if not SOCMERGED.config.server.modules.elastalertengine.useEsql %} +{% do SOCMERGED.config.server.client.detection.templateDetections.pop('elastalert_correlation', None) %} +{% do SOCMERGED.config.server.client.detections.update({'queries': SOCMERGED.config.server.client.detections.queries | rejectattr('name', 'equalto', 'Detection Type - Sigma (Elastalert) - Correlations') | list}) %} +{% endif %} + {# Define the postgresmetrics module if telegraf is setup to only use Postgres #} {% if TELEGRAFMERGED.output != 'INFLUXDB' and PG_USER and PG_PASS %} {% do SOCMERGED.config.server.modules.update({ diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 8aabbfa36..6255fbd23 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -370,6 +370,18 @@ soc: description: 'How often the ElastAlert integrity checker runs (in seconds). This verifies the integrity of deployed rules.' global: True advanced: True + partialSyncTimeoutSeconds: + description: 'How long to wait for Sigma rules to deploy after a detection is created, updated, or deleted. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: sigma + bulkSyncTimeoutSeconds: + description: 'How long to wait for Sigma rules to deploy after a bulk enable, disable, or delete has saved its detections. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: sigma rulesRepos: default: &eerulesRepos description: "Custom Git repositories to pull Sigma rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Elastalert --> Full Update." @@ -401,15 +413,27 @@ soc: advanced: False helpLink: sigma useEsql: - description: "(Pre-release) Use Elasticsearch Piped Query Language (ES|QL) instead of EQL (Elastic Query Language) for Elasticsearch queries. The Sigma converter will output ES|QL instead of EQL, allowing support for correlations." + description: "(Pre-release) Use Elasticsearch Piped Query Language (ES|QL) instead of EQL (Elastic Query Language) for Elasticsearch queries. The Sigma converter will output ES|QL instead of EQL, allowing support for correlations. Switching back to EQL is not supported for correlations." global: True advanced: True forcedType: bool esqlCaseInsensitive: - description: "Match string values case-insensitively when converting Sigma rules. Applies to ES|QL only" + description: "Match string values case-insensitively when converting Sigma rules, and group correlation values regardless of case. Applies to ES|QL only" global: True advanced: True forcedType: bool + esqlQueryDelaySeconds: + description: "Seconds ES|QL rules search behind now, so unsearchable events aren't missed. Delays alerts by the same amount. Set at least the longest index refresh interval. ES|QL only." + global: True + advanced: True + forcedType: int + helpLink: sigma + esqlCorrelationAllowanceSeconds: + description: "Extra seconds of arrivals each correlation run re-reads beyond its timespan, so a burst whose events arrive spread out is still counted together. Correlations below a threshold (lt, lte, eq, neq) and value_avg or value_percentile correlations count only the timespan ending this much plus esqlQueryDelaySeconds ago, so they alert this much later. ES|QL only." + global: True + advanced: True + forcedType: int + helpLink: sigma elastic: index: description: Comma-separated list of indices or index patterns (wildcard "*" supported) that SOC will search for records. @@ -513,6 +537,10 @@ soc: description: Enables or disables the SOC notification module. forcedType: bool global: True + connectionTimeoutSeconds: + description: Duration (in seconds) to wait for a response from the remote notification endpoint host before giving up. + forcedType: int + global: True postgres: host: description: Hostname or IP address of the PostgreSQL server used by SOC. Defaults to the manager hostname. @@ -633,6 +661,18 @@ soc: description: 'How often the Strelka integrity checker runs (in seconds). This verifies the integrity of deployed rules.' global: True advanced: True + partialSyncTimeoutSeconds: + description: 'How long to wait for YARA rules to deploy after a detection is created, updated, or deleted. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: yara + bulkSyncTimeoutSeconds: + description: 'How long to wait for YARA rules to deploy after a bulk enable, disable, or delete has saved its detections. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: yara rulesRepos: default: &serulesRepos description: "Custom Git repositories to pull YARA rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Strelka --> Full Update." @@ -697,6 +737,18 @@ soc: description: 'How often the Suricata integrity checker runs (in seconds). This verifies the integrity of deployed rules.' global: True advanced: True + partialSyncTimeoutSeconds: + description: 'How long to wait for Suricata rules to deploy after a detection is created, updated, or deleted. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: suricata + bulkSyncTimeoutSeconds: + description: 'How long to wait for Suricata rules to deploy after a bulk enable, disable, or delete has saved its detections. Must allow time for a scheduled rule sync already in progress to finish. Increase on systems with limited resources.' + global: True + advanced: True + forcedType: int + helpLink: suricata customRulesets: description: 'This setting is no longer used. Use Ruleset Sources setting instead.' global: True @@ -937,6 +989,9 @@ soc: DetectionEngineer: description: This agent manages detections and their overrides, including tuning noisy rules and authoring rule content. global: True + AlertTriage: + description: This agent triages alerts autonomously for the Alert Triage automation, ending each run with a report and an assessment of the alert. It can send a notification but cannot acknowledge alerts or escalate to cases. + global: True useMemory: description: Enables the Memory system for OnionAI global: True @@ -1025,7 +1080,7 @@ soc: forcedType: int automationSettings: tickIntervalSeconds: - description: How often, in seconds, the automation scheduler checks for automations that are due to run. Must be greater than 0. + description: How often, in seconds, the automation scheduler checks for automations that are due to run. Must be greater than 0. This value is also the default interval for new automations, however admins can override individual automation intervals to a longer value via the Agent Studio. global: True advanced: True forcedType: int @@ -1039,11 +1094,18 @@ soc: global: True advanced: True forcedType: int + turnTimeoutSeconds: + description: Maximum number of seconds a single model turn of an automation's agent session may run, even while the model is still producing output. A turn that exceeds this limit is abandoned and the session is recorded as failed. Set to 0 to disable the timeout. Edit this setting via the Agent Studio. + global: True + advanced: True + forcedType: int + readonlyUi: True alertTriageEpoch: description: The earliest alert time the Alert Triage automation will consider. Alerts before this time are never triaged, which keeps a first run on an existing deployment from working through old history. Must be in UTC format (2026-09-24T00:00:00Z). regex: '^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z)?$' regexFailureMessage: Expecting date in RFC3339 format (2026-09-24T00:00:00Z) global: True + readonlyUi: True advanced: True tools: filterEventFields: @@ -1151,6 +1213,10 @@ soc: description: Set to true to enable the Detections module in SOC. global: True forcedType: bool + allowExternalMarkdownImages: + description: Set to true to let user-written Markdown, such as case descriptions and comments, load images from other servers. Loading an image sends a request to its server, so leave this disabled unless needed; Onion AI output never loads external images. + global: True + forcedType: bool inactiveTools: description: List of external tools to remove from the SOC UI. global: True @@ -1203,6 +1269,8 @@ soc: - field: showSubtitle label: Show Query in Dropdown. forcedType: bool + - field: license + label: Only show on grids licensed for this feature, e.g. oai. An oai query also needs the assistant enabled and agentic. Leave blank to show everywhere. queryToggleFilters: description: Customize togglable query filters that apply to all queries. Exclusive toggles will invert the filter if toggled off rather than omitting the filter from the query. global: True diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index aa5b2ed31..c75be689b 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1333,8 +1333,8 @@ DISA STIG for Oracle Linux 9 V1R3. - - + + @@ -1935,8 +1935,8 @@ standard DISA STIG for Oracle Linux 9 profile. - - + + diff --git a/salt/strelka/backend/enabled.sls b/salt/strelka/backend/enabled.sls index e62349f70..ee670a2b1 100644 --- a/salt/strelka/backend/enabled.sls +++ b/salt/strelka/backend/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.backend.config - strelka.backend.sostatus @@ -17,6 +19,7 @@ strelka_backend: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-backend:{{ GLOBALS.so_version }} - restart_policy: unless-stopped - binds: + - {{ CATRUST.dir }} - /opt/so/conf/strelka/backend/:/etc/strelka/:ro - /opt/so/conf/strelka/rules/compiled/:/etc/yara/:ro {% if DOCKERMERGED.containers['so-strelka-backend'].custom_bind_mounts %} @@ -36,12 +39,14 @@ strelka_backend: - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKERMERGED.containers['so-strelka-backend'].extra_env %} - environment: - {% for XTRAENV in DOCKERMERGED.containers['so-strelka-backend'].extra_env %} + - REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt + - SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt + {% if DOCKERMERGED.containers['so-strelka-backend'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-backend'].extra_env %} - {{ XTRAENV }} - {% endfor %} - {% endif %} + {% endfor %} + {% endif %} {% if DOCKERMERGED.containers['so-strelka-backend'].ulimits %} - ulimits: {% for ULIMIT in DOCKERMERGED.containers['so-strelka-backend'].ulimits %} @@ -49,6 +54,7 @@ strelka_backend: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: strelkasensorcompiledrules - file: backend_backend_config - file: backend_logging_config diff --git a/salt/strelka/coordinator/enabled.sls b/salt/strelka/coordinator/enabled.sls index 8393d7e68..01543c93a 100644 --- a/salt/strelka/coordinator/enabled.sls +++ b/salt/strelka/coordinator/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.coordinator.config - strelka.coordinator.sostatus @@ -39,6 +41,7 @@ strelka_coordinator: {% endfor %} {% endif %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /nsm/strelka/coord-redis-data:/data:rw {% if DOCKERMERGED.containers['so-strelka-coordinator'].custom_bind_mounts %} {% for BIND in DOCKERMERGED.containers['so-strelka-coordinator'].custom_bind_mounts %} @@ -51,6 +54,9 @@ strelka_coordinator: - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} {% endfor %} {% endif %} + - watch: + - cmd: ca_trust_extract + delete_so-strelka-coordinator_so-status.disabled: file.uncomment: - name: /opt/so/conf/so-status/so-status.conf diff --git a/salt/strelka/filestream/enabled.sls b/salt/strelka/filestream/enabled.sls index c01171565..60e741e5c 100644 --- a/salt/strelka/filestream/enabled.sls +++ b/salt/strelka/filestream/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.filestream.config - strelka.filestream.sostatus @@ -17,6 +19,7 @@ strelka_filestream: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} - restart_policy: unless-stopped - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/conf/strelka/filestream/:/etc/strelka/:ro - /nsm/strelka:/nsm/strelka {% if DOCKERMERGED.containers['so-strelka-filestream'].custom_bind_mounts %} @@ -49,6 +52,7 @@ strelka_filestream: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: filestream_config delete_so-strelka-filestream_so-status.disabled: diff --git a/salt/strelka/frontend/enabled.sls b/salt/strelka/frontend/enabled.sls index f2d0eecd1..5d19961b5 100644 --- a/salt/strelka/frontend/enabled.sls +++ b/salt/strelka/frontend/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.frontend.config - strelka.frontend.sostatus @@ -17,6 +19,7 @@ strelka_frontend: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} - restart_policy: unless-stopped - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/conf/strelka/frontend/:/etc/strelka/:ro - /nsm/strelka/log/:/var/log/strelka/:rw {% if DOCKERMERGED.containers['so-strelka-frontend'].custom_bind_mounts %} @@ -54,6 +57,7 @@ strelka_frontend: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: frontend_config delete_so-strelka-frontend_so-status.disabled: diff --git a/salt/strelka/gatekeeper/enabled.sls b/salt/strelka/gatekeeper/enabled.sls index 19d74a6d8..507e1fe02 100644 --- a/salt/strelka/gatekeeper/enabled.sls +++ b/salt/strelka/gatekeeper/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.gatekeeper.config - strelka.gatekeeper.sostatus @@ -33,6 +35,7 @@ strelka_gatekeeper: - {{ BINDING }} {% endfor %} - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /nsm/strelka/gk-redis-data:/data:rw {% if DOCKERMERGED.containers['so-strelka-gatekeeper'].custom_bind_mounts %} {% for BIND in DOCKERMERGED.containers['so-strelka-gatekeeper'].custom_bind_mounts %} @@ -51,6 +54,8 @@ strelka_gatekeeper: - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} {% endfor %} {% endif %} + - watch: + - cmd: ca_trust_extract delete_so-strelka-gatekeeper_so-status.disabled: file.uncomment: diff --git a/salt/strelka/manager/enabled.sls b/salt/strelka/manager/enabled.sls index 272767928..d0fb3d07d 100644 --- a/salt/strelka/manager/enabled.sls +++ b/salt/strelka/manager/enabled.sls @@ -7,8 +7,10 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} include: + - ca.trust - strelka.manager.config - strelka.manager.sostatus @@ -17,6 +19,7 @@ strelka_manager: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} - restart_policy: unless-stopped - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/conf/strelka/manager/:/etc/strelka/:ro {% if DOCKERMERGED.containers['so-strelka-manager'].custom_bind_mounts %} {% for BIND in DOCKERMERGED.containers['so-strelka-manager'].custom_bind_mounts %} @@ -48,6 +51,7 @@ strelka_manager: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: manager_config delete_so-strelka-manager_so-status.disabled: diff --git a/salt/suricata/enabled.sls b/salt/suricata/enabled.sls index d9206798e..ede2c1d31 100644 --- a/salt/suricata/enabled.sls +++ b/salt/suricata/enabled.sls @@ -6,11 +6,13 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'suricata/map.jinja' import SURICATAMERGED %} include: + - ca.trust - suricata.config - suricata.sostatus @@ -33,6 +35,7 @@ so-suricata: {% endfor %} {% endif %} - binds: + - {{ CATRUST.dir }} - /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro - /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro - /opt/so/conf/suricata/classification.config:/etc/suricata/classification.config:ro @@ -55,6 +58,7 @@ so-suricata: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: suriconfig - file: surithresholding - file: /opt/so/conf/suricata/bpf diff --git a/salt/tcpreplay/init.sls b/salt/tcpreplay/init.sls index f5b1b05d9..076f0f42c 100644 --- a/salt/tcpreplay/init.sls +++ b/salt/tcpreplay/init.sls @@ -2,6 +2,10 @@ {% if sls in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} + +include: + - ca.trust so-tcpreplay: docker_container.running: @@ -13,7 +17,10 @@ so-tcpreplay: - interactive: True - tty: True - binds: + - {{ CATRUST.dir }} - /opt/so/samples:/opt/so/samples:ro + - watch: + - cmd: ca_trust_extract {% else %} diff --git a/salt/telegraf/enabled.sls b/salt/telegraf/enabled.sls index addc55128..9fdb4ec46 100644 --- a/salt/telegraf/enabled.sls +++ b/salt/telegraf/enabled.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'telegraf/map.jinja' import TELEGRAFMERGED %} @@ -33,6 +34,7 @@ so-telegraf: - network_mode: host - init: True - binds: + - {{ CATRUST.pem }}:/etc/ssl/certs/ca-certificates.crt:ro - /opt/so/log/telegraf:/var/log/telegraf:rw - /opt/so/conf/telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro - /opt/so/conf/telegraf/node_config.json:/etc/telegraf/node_config.json:ro @@ -73,6 +75,7 @@ so-telegraf: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: tgraf_sbin_jinja - file: lasthighstate_placeholder - file: trusttheca diff --git a/salt/zeek/enabled.sls b/salt/zeek/enabled.sls index ec8148e90..c4a191d89 100644 --- a/salt/zeek/enabled.sls +++ b/salt/zeek/enabled.sls @@ -6,10 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/trust.map.jinja' import CATRUST %} {% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca.trust - zeek.config - zeek.sostatus @@ -30,6 +32,7 @@ so-zeek: {% endfor %} {% endif %} - binds: + - {{ CATRUST.dir }} - /nsm/zeek/logs:/nsm/zeek/logs:rw - /nsm/zeek/spool:/nsm/zeek/spool:rw - /nsm/zeek/extracted:/nsm/zeek/extracted:rw @@ -63,6 +66,7 @@ so-zeek: {% endfor %} {% endif %} - watch: + - cmd: ca_trust_extract - file: /opt/so/conf/zeek/local.zeek - file: /opt/so/conf/zeek/node.cfg - file: /opt/so/conf/zeek/networks.cfg diff --git a/setup/so-functions b/setup/so-functions index 41be9c7a7..0381b6252 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -976,27 +976,50 @@ docker_seed_update() { set_progress_str "$docker_seed_update_percent" "Downloading $name" } +registry_tar_has_soversion() { + local tarfile=$1 + local version=$2 + + [ -n "$version" ] || return 1 + [ -f "$tarfile" ] || return 1 + # grep -q in a pipe SIGPIPEs tar; under pipefail a match would look like failure. + grep -qF "/_manifests/tags/${version}/" < <(tar -tf "$tarfile" 2>/dev/null) +} + docker_seed_registry() { local VERSION="$SOVERSION" + local REGISTRY_TAR=/nsm/docker-registry/docker/registry.tar - if [ -f /nsm/docker-registry/docker/registry.tar ]; then - logCmd "tar xvf /nsm/docker-registry/docker/registry.tar -C /nsm/docker-registry/docker" - logCmd "rm /nsm/docker-registry/docker/registry.tar" + if [ -f "$REGISTRY_TAR" ] && registry_tar_has_soversion "$REGISTRY_TAR" "$VERSION"; then + info "Extracting $REGISTRY_TAR" + if ! tar xvf "$REGISTRY_TAR" -C /nsm/docker-registry/docker >> "$setup_log" 2>&1; then + error "Failed to extract $REGISTRY_TAR" + return 1 + fi + logCmd "rm -f $REGISTRY_TAR" + return 0 + elif [ -f "$REGISTRY_TAR" ]; then + info "Not using $REGISTRY_TAR; it has no images tagged '${VERSION}'" + if [[ "$is_airgap" == true ]]; then + error "Airgap install: $REGISTRY_TAR does not match Security Onion version '${VERSION}'. Use the ISO for this version." + return 1 + fi elif [[ -d /nsm/docker-registry/docker/registry && ( -f /etc/SOCLOUD || "$is_airgap" == true ) ]]; then echo "Using existing docker registry content" - else - if [ "$install_type" == 'IMPORT' ]; then - container_list 'so-import' - else - container_list - fi - - docker_seed_update_percent=25 - - update_docker_containers 'netinstall' '' 'docker_seed_update' '/dev/stdout' 2>&1 | tee -a "$setup_log" - # Use pipe exit status of 'update_docker_containers' for return code - return ${PIPESTATUS[0]} + return 0 fi + + if [ "$install_type" == 'IMPORT' ]; then + container_list 'so-import' + else + container_list + fi + + docker_seed_update_percent=25 + + update_docker_containers 'netinstall' '' 'docker_seed_update' '/dev/stdout' 2>&1 | tee -a "$setup_log" + # Use pipe exit status of 'update_docker_containers' for return code + return ${PIPESTATUS[0]} } elasticfleet_pillar() { @@ -1362,7 +1385,11 @@ create_global() { echo "global:" >> $global_pillar_file echo " soversion: '$SOVERSION'" >> $global_pillar_file echo " managerip: '$MAINIP'" >> $global_pillar_file - echo " mdengine: 'ZEEK'" >> $global_pillar_file + if [[ $is_eval ]] || [ "$install_type" = 'EVAL' ]; then + echo " mdengine: 'SURICATA'" >> $global_pillar_file + else + echo " mdengine: 'ZEEK'" >> $global_pillar_file + fi echo " ids: 'Suricata'" >> $global_pillar_file echo " url_base: '$REDIRECTIT'" >> $global_pillar_file if [[ $is_airgap ]]; then diff --git a/setup/so-verify b/setup/so-verify index 660424c72..0cd910021 100755 --- a/setup/so-verify +++ b/setup/so-verify @@ -67,7 +67,7 @@ log_has_errors() { grep -vE "Reading first line of patchfile" | \ grep -vE "Command failed with exit code" | \ grep -vE "Running scope as unit" | \ - grep -vE "securityonion-resources/sigma/stable" | \ + grep -vE "securityonion-resources/sigma/" | \ grep -vE "remove_failed_vm.sls" | \ grep -vE "failed to copy: httpReadSeeker" | \ grep -vE "Error response from daemon: failed to resolve reference" | \ diff --git a/sigs/securityonion-3.4.0-20261102.iso.sig b/sigs/securityonion-3.4.0-20261102.iso.sig new file mode 100644 index 000000000..f838bb936 Binary files /dev/null and b/sigs/securityonion-3.4.0-20261102.iso.sig differ