Commit 16a5962
[Security Solution] Add Sentinel watchlist lookup ingestion (elastic#269726)
## Summary
Adds Microsoft Sentinel watchlist ingestion to the SIEM rule migration
lookup upload flow. Sentinel watchlist ARM exports are validated in the
UI, uploaded as raw JSON, normalized in the backend, and ingested
through the existing generic processLookups path.
This supports both direct watchlist ARM resources and one-resource ARM
deployment templates, rejects unsupported non-CSV watchlists,
denormalizes only the itemsSearchKey column, and stores itemsSearchKey
in resource metadata.
## Sentinal Watchlist handling
Sentinel watchlists are exported as ARM JSON resources, with the actual
lookup data stored as CSV in `properties.rawContent` ( See
[example](https://github.com/Azure/Azure-Sentinel/blob/840f0f490c3509335821e2030deca714d00c2760/Solutions/Network%20Session%20Essentials/Watchlists/NetworkSession_Monitor_Configuration.json#L13)
).
During upload, Kibana validates the ARM JSON, extracts the CSV, parses
it into rows, and converts the watchlist into a normal lookup resource.
However, before creating the Elastic lookup index, it denormalizes the
Sentinel `itemsSearchKey` column. In simple terms, if the search key
cell contains multiple comma-separated values, Kibana creates one lookup
row per value.
For the Network Session Essentials example, the watchlist declares:
```json
{
"watchlistAlias": "NetworkSession_Monitor_Configuration",
"itemsSearchKey": "Ports",
"contentType": "text/csv"
}
```
That means `Ports` is the field rules search against, so only `Ports` is
denormalized.
### Watchlist before normalization
| Ports | App | Name |
|---|---|---|
| `389,636` | `*` | `Suspicious LDAP Traffic` |
| `3389` | `*` | `Suspicious Remote Desktop Network Traffic` |
| `9150,9151` | `tor` | `Suspicious TOR Traffic` |
| `139,445` | `smb` | `Suspicious SMB Traffic` |
### Watchlist after normalization
| Ports | App | Name |
|---|---|---|
| `389` | `*` | `Suspicious LDAP Traffic` |
| `636` | `*` | `Suspicious LDAP Traffic` |
| `3389` | `*` | `Suspicious Remote Desktop Network Traffic` |
| `9150` | `tor` | `Suspicious TOR Traffic` |
| `9151` | `tor` | `Suspicious TOR Traffic` |
| `139` | `smb` | `Suspicious SMB Traffic` |
| `445` | `smb` | `Suspicious SMB Traffic` |
### Why denormalization is needed
In the Sentinel rule export
`network_session_essentials_rules_export.arm.json`, the KustoQL query
loads the watchlist, splits comma-separated fields, expands them, and
then joins event data against the expanded mapping:
```kusto
let mapping = _GetWatchlist('NetworkSession_Monitor_Configuration')
| where Type == "Detection" and ThresholdType == "Static" and Severity != "Disabled"
| extend Ports = split(Ports, ",")
| mv-expand Ports
| extend Ports = tostring(Ports);
```
This works in KustoQL because the query can build a temporary `mapping`
table, transform the watchlist inline, expand multi-value cells with
`mv-expand`, and join using a flexible condition like `Ports has
tostring(DstPortNumber)`.
ES|QL lookup joins are more constrained. `LOOKUP JOIN` joins against a
stored lookup index, not an inline transformed table, and lookup join
fields with multi-valued entries do not match. So a lookup document
where `Ports` is `"389,636"` will not behave like two separate values
when joining against an event port such as `389`.
Denormalizing during ingestion moves that transformation out of the
query and into lookup index creation. The migrated ES|QL can then use a
normal lookup join because each searchable port value exists as its own
lookup row.
## Test plan
### Cypress coverage
- ✅ TC1: Create a Microsoft Sentinel migration and identify missing
watchlists in the `Upload watchlists` step.
Steps:
1. Log in to Kibana and go to **Security** → **Automatic migrations** →
**Manage Automatic Migrations**.
2. Open **Migrate your existing SIEM rules to Elastic** and click
**Upload rules**.
3. In the **Upload SIEM rules** flyout, choose **Microsoft Sentinel**
from **Select migration source**.
4. In **Upload rules**, select a Sentinel Analytics Rules ARM JSON
export that references a watchlist.
5. Click **Upload**.
Expectations:
1. The rules upload succeeds.
2. The flyout advances to **Upload watchlists**.
3. The watchlist step explains that watchlists were found in the
uploaded rules.
4. The missing watchlist list includes the Sentinel watchlist name, for
example `HighValueAccounts` or `NetworkSession_Monitor_Configuration`
depending on the fixture.
5. The flow does not show Splunk-only macro wording for the Sentinel
migration source.
- ✅ TC2: Upload a valid Microsoft Sentinel watchlist ARM export from the
UI.
Steps:
1. Log in to Kibana and go to **Security** → **Automatic migrations** →
**Manage Automatic Migrations**.
2. Create or open a Microsoft Sentinel rule migration that is waiting on
**Upload watchlists**.
3. In the **Upload SIEM rules** flyout, go to **Upload watchlists**.
4. In the watchlist file picker labeled **Select or drag and drop the
exported watchlist files**, select a valid Sentinel watchlist ARM
export.
5. Click **Upload**.
Expectations:
1. The watchlist upload succeeds.
2. The uploaded watchlist is accepted as a Sentinel watchlist resource.
3. The missing watchlist is marked as resolved in the list.
4. The **Translate** button is available so the user can continue the
migration.
5. No watchlist parsing or unsupported content type error is shown.
- ✅ TC4: Show a user-facing error for unsupported Sentinel watchlist
content types.
Steps:
1. Log in to Kibana and go to **Security** → **Automatic migrations** →
**Manage Automatic Migrations**.
2. Click **Upload rules** and create a Microsoft Sentinel migration by
uploading a Sentinel Analytics Rules ARM JSON export that references a
watchlist.
3. Wait for the flyout to advance to **Upload watchlists**.
4. Select a Sentinel watchlist ARM JSON file where
`properties.contentType` is `application/json` instead of `text/csv`.
5. Click **Upload**.
Expectations:
1. The upload fails with a visible error for unsupported Sentinel
watchlist content type.
2. The watchlist remains unresolved in the missing watchlist list.
3. The user stays in the **Upload watchlists** step.
4. The user can choose another file and retry.
5. No lookup index is created from the unsupported watchlist file.
- ✅ TC5: Show a user-facing error for invalid Sentinel watchlist JSON.
Steps:
1. Log in to Kibana and go to **Security** → **Automatic migrations** →
**Manage Automatic Migrations**.
2. Click **Upload rules** and create a Microsoft Sentinel migration by
uploading a Sentinel Analytics Rules ARM JSON export that references a
watchlist.
3. Wait for the flyout to advance to **Upload watchlists**.
4. In the watchlist file picker, select a malformed JSON file.
5. Repeat with a valid JSON file that is not a Sentinel watchlist ARM
resource or one-resource ARM deployment template.
Expectations:
1. Malformed JSON shows **Sentinel watchlist must be valid JSON.**
2. Wrong-schema JSON shows the Sentinel watchlist ARM/template
validation error.
3. No watchlist is marked as uploaded.
4. The user remains on **Upload watchlists**.
5. The user can remove the invalid file and retry with a valid Sentinel
watchlist export.
Cypress spec:
`x-pack/solutions/security/test/security_solution_cypress/cypress/e2e/investigations/siem_migrations/rules/sentinel_onboarding.cy.ts`
### Checklist
- [x] Any text added follows EUI writing guidelines, uses sentence case
text and includes i18n support
- [ ] Documentation was added for features that require explanation or
tutorials
- [x] Unit or functional tests were updated or added to match the most
common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the docker list
- [x] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee
- [ ] Flaky Test Runner was used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct release_note label is applied per the guidelines
- [ ] Review the backport guidelines and apply applicable backport
labels.
### Identify risks
- [ ] See the risk examples in RISK_MATRIX.mdx
- [x] Low risk: Sentinel watchlist uploads are newly handled on the
existing resources endpoint. Existing Splunk and QRadar lookup behavior
remains on the existing generic lookup path.
- [x] Low risk: malformed Sentinel ARM resources or unsupported
contentType values are rejected with 400 responses rather than being
ingested.
- [x] Low risk: denormalization changes only the Sentinel itemsSearchKey
column before lookup index creation and is covered by unit and FTR API
tests.
### Release note
> Adds Microsoft Sentinel watchlist upload support to SIEM rule
migrations.
Suggested label: release_note:enhancement
---------
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent 8816ba3 commit 16a5962
24 files changed
Lines changed: 1035 additions & 35 deletions
File tree
- x-pack/solutions/security
- plugins/security_solution
- common/siem_migrations/model
- vendor/common
- public/siem_migrations
- common/components/migration_steps/lookups
- lookups_file_upload
- missing_lookups_list
- utils
- rules/components/data_input_flyout/steps/lookups/sub_steps
- lookups_file_upload
- missing_lookups_list
- server/lib/siem_migrations/rules
- api/resources
- vendors/sentinel
- test
- security_solution_api_integration/test_suites/siem_migrations
- rules/trial_license_complete_tier/rule_migrations
- resources/sentinel
- utils
- security_solution_cypress/cypress
- e2e/investigations/siem_migrations/rules
- screens
- tasks
Lines changed: 7 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
284 | 285 | | |
285 | 286 | | |
286 | 287 | | |
287 | | - | |
288 | | - | |
| 288 | + | |
| 289 | + | |
289 | 290 | | |
290 | | - | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
291 | 295 | | |
292 | 296 | | |
293 | 297 | | |
| |||
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
242 | | - | |
| 242 | + | |
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
246 | 246 | | |
| 247 | + | |
247 | 248 | | |
248 | 249 | | |
249 | 250 | | |
| |||
Lines changed: 72 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
Lines changed: 67 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
Lines changed: 35 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
90 | 91 | | |
91 | 92 | | |
92 | 93 | | |
93 | 94 | | |
94 | 95 | | |
95 | 96 | | |
96 | 97 | | |
| 98 | + | |
97 | 99 | | |
98 | 100 | | |
99 | 101 | | |
100 | 102 | | |
101 | 103 | | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
108 | 127 | | |
| 128 | + | |
| 129 | + | |
109 | 130 | | |
| 131 | + | |
110 | 132 | | |
111 | 133 | | |
112 | 134 | | |
| |||
117 | 139 | | |
118 | 140 | | |
119 | 141 | | |
| 142 | + | |
120 | 143 | | |
121 | 144 | | |
122 | 145 | | |
| |||
129 | 152 | | |
130 | 153 | | |
131 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
132 | 158 | | |
133 | | - | |
| 159 | + | |
134 | 160 | | |
135 | 161 | | |
136 | 162 | | |
| |||
Lines changed: 24 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
53 | 71 | | |
54 | 72 | | |
55 | 73 | | |
| |||
74 | 92 | | |
75 | 93 | | |
76 | 94 | | |
77 | | - | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
78 | 100 | | |
79 | | - | |
| 101 | + | |
80 | 102 | | |
81 | 103 | | |
82 | 104 | | |
| |||
Lines changed: 0 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | 43 | | |
52 | 44 | | |
53 | 45 | | |
| |||
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
0 commit comments