Skip to content

Commit f9e2940

Browse files
authored
Merge pull request #11676 from Security-Onion-Solutions/feature/sublime_platform_integration
Sublime Platform Integration
2 parents 6492694 + f33079f commit f9e2940

File tree

8 files changed

+207
-7
lines changed

8 files changed

+207
-7
lines changed

salt/elasticfleet/config.sls

+42-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{% from 'allowed_states.map.jinja' import allowed_states %}
77
{% from 'vars/globals.map.jinja' import GLOBALS %}
88
{% if sls.split('.')[0] in allowed_states %}
9+
{% set node_data = salt['pillar.get']('node_data') %}
910
1011
# Add EA Group
1112
elasticfleetgroup:
@@ -92,13 +93,53 @@ eaintegration:
9293
- user: 947
9394
- group: 939
9495
96+
eaoptionalintegrationsdir:
97+
file.directory:
98+
- name: /opt/so/conf/elastic-fleet/integrations-optional
99+
- user: 947
100+
- group: 939
101+
- makedirs: True
102+
103+
{% for minion in node_data %}
104+
{% set role = node_data[minion]["role"] %}
105+
{% if role in [ "fleet","heavynode", "manager","managersearch","standalone" ] %}
106+
{% set optional_integrations = salt['pillar.get']('elasticfleet:optional_integrations', {}) %}
107+
{% set integration_keys = salt['pillar.get']('elasticfleet:optional_integrations', {}).keys() %}
108+
fleet_server_integrations_{{ minion }}:
109+
file.directory:
110+
- name: /opt/so/conf/elastic-fleet/integrations-optional/FleetServer_{{ minion }}
111+
- user: 947
112+
- group: 939
113+
- makedirs: True
114+
{% for integration in integration_keys %}
115+
{% if 'enabled_nodes' in optional_integrations[integration]%}
116+
{% set enabled_nodes = optional_integrations[integration]["enabled_nodes"] %}
117+
{% if minion in enabled_nodes %}
118+
optional_integrations_dynamic_{{ minion }}_{{ integration }}:
119+
file.managed:
120+
- name: /opt/so/conf/elastic-fleet/integrations-optional/FleetServer_{{ minion }}/{{ integration }}.json
121+
- source: salt://elasticfleet/files/integrations-optional/{{ integration }}.json
122+
- user: 947
123+
- group: 939
124+
- template: jinja
125+
- defaults:
126+
NAME: {{ minion }}
127+
{% else %}
128+
optional_integrations_dynamic_{{ minion }}_{{ integration }}_delete:
129+
file.absent:
130+
- name: /opt/so/conf/elastic-fleet/integrations-optional/FleetServer_{{ minion }}/{{ integration }}.json
131+
{% endif %}
132+
{% endif %}
133+
{% endfor %}
134+
{% endif %}
135+
{% endfor %}
95136
ea-integrations-load:
96137
file.absent:
97138
- name: /opt/so/state/eaintegrations.txt
98139
- onchanges:
99140
- file: eaintegration
100141
- file: eadynamicintegration
101-
- file: eapackageupgrade
142+
- file: /opt/so/conf/elastic-fleet/integrations-optional/*
102143
{% endif %}
103144
{% else %}
104145

salt/elasticfleet/defaults.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,10 @@ elasticfleet:
9090
- zscaler_zia
9191
- zscaler_zpa
9292
- 1password
93+
optional_integrations:
94+
sublime_platform:
95+
enabled_nodes: []
96+
api_key:
97+
base_url: https://api.platform.sublimesecurity.com
98+
poll_interval: 5m
99+
limit: 100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{%- from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED -%}
2+
{%- from 'sensoroni/map.jinja' import SENSORONIMERGED -%}
3+
{%- from 'vars/globals.map.jinja' import GLOBALS -%}
4+
{%- raw -%}
5+
{
6+
"package": {
7+
"name": "httpjson",
8+
"version": ""
9+
},
10+
"name": "sublime-platform",
11+
"namespace": "default",
12+
"description": "",
13+
"policy_id": "FleetServer_{%- endraw -%}{{ NAME }}{%- raw -%}",
14+
"vars": {},
15+
"inputs": {
16+
"generic-httpjson": {
17+
"enabled": true,
18+
"streams": {
19+
"httpjson.generic": {
20+
"enabled": true,
21+
"vars": {
22+
"request_method": "GET",
23+
"processors": "- drop_event:\n when:\n not:\n contains: \n message: \"flagged_rules\"\n- decode_json_fields:\n fields: [\"message\"]\n document_id: id\n target: \"\"",
24+
"enable_request_tracer": false,
25+
"oauth_scopes": [],
26+
"request_transforms": "- set:\n target: header.Authorization\n value: 'Bearer {% endraw -%}{{ ELASTICFLEETMERGED.optional_integrations.sublime_platform.api_key }}{%- raw -%}'\n- set:\n target: header.accept\n value: application/json\n- set:\n target: url.params.last_message_created_at[gte]\n value: '[[formatDate (now (parseDuration \"-{%- endraw -%}{{ ELASTICFLEETMERGED.optional_integrations.sublime_platform.poll_interval }}{%- raw -%}\")) \"2006-01-02T15:04:05Z\"]]'\n- set:\n target: url.params.reviewed\n value: false\n- set:\n target: url.params.flagged\n value: true\n- set:\n target: url.params.limit\n value: {% endraw %}{{ ELASTICFLEETMERGED.optional_integrations.sublime_platform.limit }}{%- raw -%}",
27+
"response_transforms": "",
28+
"request_redirect_headers_ban_list": [],
29+
"request_encode_as": "application/x-www-form-urlencoded",
30+
"request_url": "{%- endraw -%}{{ ELASTICFLEETMERGED.optional_integrations.sublime_platform.base_url }}{%- raw -%}/v0/message-groups",
31+
"response_split": "target: body.message_groups\ntype: array\nkeep_parent: false\ntransforms:\n - set:\n target: body.sublime.request_url\n value : '[[ .last_response.url.value ]]'",
32+
"tags": [
33+
"forwarded"
34+
],
35+
"pipeline": "sublime",
36+
"data_stream.dataset": "sublime",
37+
"request_interval": "1m"
38+
}
39+
}
40+
}
41+
}
42+
}
43+
}
44+
{%- endraw -%}

salt/elasticfleet/soc_elasticfleet.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,36 @@ elasticfleet:
4040
helpLink: elastic-fleet.html
4141
sensitive: True
4242
advanced: True
43+
optional_integrations:
44+
sublime_platform:
45+
enabled_nodes:
46+
description: Fleet nodes with the Sublime Platform integration enabled. Enter one per line.
47+
global: True
48+
helpLink: elastic-fleet.html
49+
advanced: True
50+
forcedType: "[]string"
51+
api_key:
52+
description: API key for Sublime Platform.
53+
global: True
54+
helpLink: elastic-fleet.html
55+
advanced: True
56+
forcedType: string
57+
sensitive: True
58+
base_url:
59+
description: Base URL for Sublime Platform.
60+
global: True
61+
helpLink: elastic-fleet.html
62+
advanced: True
63+
forcedType: string
64+
poll_interval:
65+
description: Poll interval for alerts from Sublime Platform.
66+
global: True
67+
helpLink: elastic-fleet.html
68+
advanced: True
69+
forcedType: string
70+
limit:
71+
description: The maximum number of message groups to return from Sublime Platform.
72+
global: True
73+
helpLink: elastic-fleet.html
74+
advanced: True
75+
forcedType: int

salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load

+22-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,28 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then
6464
if [[ "$RETURN_CODE" != "1" ]]; then
6565
touch /opt/so/state/eaintegrations.txt
6666
fi
67+
68+
# Fleet Server - Optional integrations
69+
for INTEGRATION in /opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json
70+
do
71+
if ! [ "$INTEGRATION" == "/opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json" ]; then
72+
FLEET_POLICY=`echo "$INTEGRATION"| cut -d'/' -f7`
73+
printf "\n\nFleet Server Policy - Loading $INTEGRATION\n"
74+
elastic_fleet_integration_check "$FLEET_POLICY" "$INTEGRATION"
75+
if [ -n "$INTEGRATION_ID" ]; then
76+
printf "\n\nIntegration $NAME exists - Updating integration\n"
77+
elastic_fleet_integration_update "$INTEGRATION_ID" "@$INTEGRATION"
78+
else
79+
printf "\n\nIntegration does not exist - Creating integration\n"
80+
if [ "$NAME" != "elasticsearch-logs" ]; then
81+
elastic_fleet_integration_create "@$INTEGRATION"
82+
fi
83+
fi
84+
fi
85+
done
86+
if [[ "$RETURN_CODE" != "1" ]]; then
87+
touch /opt/so/state/eaintegrations.txt
88+
fi
6789
else
6890
exit $RETURN_CODE
6991
fi
70-
71-
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"description" : " Email alerts from Sublime",
3+
"processors" : [
4+
{ "set": { "field": "event.module", "value": "sublime" } },
5+
{ "set": { "field": "event.dataset", "value": "alert" } },
6+
{ "set": { "field": "event.severity", "value": 3, "override": true } },
7+
{ "set": { "field": "rule.name", "value": "Sublime Platform: {{ flagged_rules.0.name }}", "override": true } },
8+
{ "set": { "field": "sublime.message_group_id", "value": "{{ _id }}", "override": true } },
9+
{ "set": { "field": "email.address", "value": "{{ messages.0.recipients.0.email }}", "override": true } },
10+
{ "set": { "field": "email.forwarded_recipents", "value": "{{ messages.0.forwarded_receipients }}", "override": true } },
11+
{ "set": { "field": "email.sender.address", "value": "{{ messages.0.sender.email }}", "override": true } },
12+
{ "set": { "field": "email.subject", "value": "{{ messages.0.subject }}", "override": true } },
13+
{ "set": { "field": "email.forwarded_at", "value": "{{ messages.0.forwarded_at }}", "override": true } },
14+
{ "set": { "field": "email.created_at", "value": "{{ messages.0.created_at }}", "override": true } },
15+
{ "set": { "field": "email.read_at", "value": "{{ messages.0.read_at }}", "override": true } },
16+
{ "set": { "field": "email.replied_at", "value": "{{ messages.0.replied_at }}", "override": true } },
17+
{
18+
"grok": {
19+
"field": "sublime.request_url",
20+
"patterns": ["^https://api.%{DATA:sublime_host}/v0%{GREEDYDATA}$"],
21+
"ignore_failure": true
22+
}
23+
},
24+
25+
{ "rename": { "field": "sublime_host", "target_field": "sublime.url", "ignore_missing": true } },
26+
{ "rename": { "field": "data", "target_field": "sublime", "ignore_missing": true } },
27+
{ "rename": { "field": "flagged_rules", "target_field": "sublime.flagged_rules", "ignore_missing": true } },
28+
{ "rename": { "field": "organization_id", "target_field": "sublime.organization_id", "ignore_missing": true } },
29+
{ "rename": { "field": "review_status", "target_field": "sublime.review_status", "ignore_missing": true } },
30+
{ "rename": { "field": "state", "target_field": "sublime.state", "ignore_missing": true } },
31+
{ "rename": { "field": "user_reports", "target_field": "sublime.user_reports", "ignore_missing": true } },
32+
{ "pipeline": { "name": "common" } }
33+
]
34+
}

salt/logstash/pipelines/config/so/9805_output_elastic_agent.conf.jinja

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
output {
22
if "elastic-agent" in [tags] {
3-
if [metadata][pipeline] {
3+
if [metadata][pipeline] {
4+
if [metadata][_id] {
45
elasticsearch {
56
hosts => "{{ GLOBALS.manager }}"
67
ecs_compatibility => v8
78
data_stream => true
89
user => "{{ ES_USER }}"
910
password => "{{ ES_PASS }}"
11+
document_id => "%{[metadata][_id]}"
1012
pipeline => "%{[metadata][pipeline]}"
13+
silence_errors_in_log => ["version_conflict_engine_exception"]
1114
ssl => true
1215
ssl_certificate_verification => false
1316
}
@@ -19,10 +22,22 @@ output {
1922
data_stream => true
2023
user => "{{ ES_USER }}"
2124
password => "{{ ES_PASS }}"
25+
pipeline => "%{[metadata][pipeline]}"
2226
ssl => true
23-
ssl_certificate_verification => false
27+
ssl_certificate_verification => false
2428
}
25-
}
29+
}
30+
}
31+
else {
32+
elasticsearch {
33+
hosts => "{{ GLOBALS.manager }}"
34+
ecs_compatibility => v8
35+
data_stream => true
36+
user => "{{ ES_USER }}"
37+
password => "{{ ES_PASS }}"
38+
ssl => true
39+
ssl_certificate_verification => false
40+
}
41+
}
2642
}
2743
}
28-

salt/soc/defaults.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ soc:
5959
target: _blank
6060
links:
6161
- 'https://www.virustotal.com/gui/search/{value}'
62+
- name: Sublime Platform Email Review
63+
description: Review email in Sublime Platform
64+
icon: fa-external-link-alt
65+
target: _blank
66+
links:
67+
- 'https://{:sublime.url}/messages/{:sublime.message_group_id}'
6268
eventFields:
6369
default:
6470
- soc_timestamp

0 commit comments

Comments
 (0)