Skip to content

Commit e453f03

Browse files
authored
Merge pull request #14635 from adutt-commvault/changeapi2
Commvault Security IQ: Migrate data connector to Codeless Connector Framework (CCF)
2 parents 6c45efc + 71de33e commit e453f03

15 files changed

Lines changed: 1338 additions & 133 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"Name": "CommvaultAlertsCCF_CL",
3+
"properties":
4+
[
5+
{
6+
"Name": "TimeGenerated",
7+
"Type": "Datetime"
8+
},
9+
{
10+
"Name": "RefTime",
11+
"Type": "Long"
12+
},
13+
{
14+
"Name": "AnomalyType",
15+
"Type": "Int"
16+
},
17+
{
18+
"Name": "CreateCount",
19+
"Type": "Int"
20+
},
21+
{
22+
"Name": "DeleteCount",
23+
"Type": "Int"
24+
},
25+
{
26+
"Name": "ModCount",
27+
"Type": "Int"
28+
},
29+
{
30+
"Name": "RenameCount",
31+
"Type": "Int"
32+
},
33+
{
34+
"Name": "InfectedFilesCount",
35+
"Type": "Int"
36+
},
37+
{
38+
"Name": "ApplicationSizeMB",
39+
"Type": "Real"
40+
},
41+
{
42+
"Name": "BackupSizeMB",
43+
"Type": "Real"
44+
},
45+
{
46+
"Name": "Location",
47+
"Type": "String"
48+
},
49+
{
50+
"Name": "ClientName",
51+
"Type": "String"
52+
},
53+
{
54+
"Name": "ClientId",
55+
"Type": "Int"
56+
}
57+
]
58+
}

.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
"Workday",
289289
"SamsungDCDefinition",
290290
"CommvaultSecurityIQ_CL",
291+
"CommvaultSecurityIQConnector",
291292
"ExtraHop",
292293
"ContrastADR",
293294
"CyfirmaAttackSurfaceAlertsConnector",

Solutions/Commvault Security IQ/Analytic Rules/CommvaultSecurityIQ_Alert.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ severity: Medium
66
status: Available
77
enabled: true
88
requiredDataConnectors:
9-
- connectorId: CommvaultSecurityIQ_CL
9+
- connectorId: CommvaultSecurityIQConnector
1010
datatypes:
11-
- CommvaultAlerts_CL
11+
- CommvaultAlertsCCF_CL
1212
queryFrequency: 5m
1313
queryPeriod: 5m
1414
triggerOperator: gt
@@ -17,12 +17,13 @@ tactics:
1717
- DefenseEvasion
1818
- Impact
1919
customDetails:
20-
Client: HostName
20+
Client: ClientName
21+
AnomalyType: AnomalyType
2122
eventGroupingSettings:
2223
aggregationKind: AlertPerResult
2324
alertDetailsOverride:
24-
alertDisplayNameFormat: 'Alert from Commvault Cloud for Event ID: {{EventId}}'
25-
alertDescriptionFormat: 'Alert from Commvault Cloud for Event ID: {{EventId}}. Event Description: {{Description}}. Check the event description on Commvault Command Center for more details.'
25+
alertDisplayNameFormat: 'Commvault Cloud Anomaly detected for client: {{ClientName}}'
26+
alertDescriptionFormat: 'Anomaly detected for Commvault client {{ClientName}}. AnomalyType flag: {{AnomalyType}}.'
2627
alertDynamicProperties: []
2728
relevantTechniques:
2829
- T1578
@@ -33,11 +34,10 @@ tags:
3334
- Threat Intelligence
3435
- Ransomware
3536
query: |
36-
let TargetEventCodes = dynamic(["7:211", "7:212", "7:293", "7:269", "14:337", "14:338", "69:59", "7:333", "69:60", "35:5575", "35:5636", "7:349", "17:193", "17:195"]);
37-
CommvaultAlerts_CL
37+
CommvaultAlertsCCF_CL
3838
| where TimeGenerated > ago(5m)
39-
| where EventCode in (TargetEventCodes)
39+
| where isnotnull(AnomalyType) and AnomalyType > 0
4040
| take 1000
4141
entityMappings: null
42-
version: 1.0.5
42+
version: 1.0.6
4343
kind: Scheduled
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
{
2+
"name": "CommvaultSecurityIQConnector",
3+
"apiVersion": "2025-07-01-preview",
4+
"type": "Microsoft.SecurityInsights/dataConnectorDefinitions",
5+
"location": "{{location}}",
6+
"kind": "Customizable",
7+
"properties": {
8+
"connectorUiConfig": {
9+
"id": "CommvaultSecurityIQConnector",
10+
"title": "Commvault Security IQ (via Codeless Connector Framework)",
11+
"publisher": "Commvault",
12+
"descriptionMarkdown": "The Commvault Security IQ data connector ingests threat indicator anomaly events from the Commvault `/Client/Anomaly` API into Microsoft Sentinel. Each record in `CommvaultAlertsCCF_CL` corresponds to one entry in the `anomalyClients` array and captures fields such as `AnomalyType` (a bitfield — 64=Ransomware, 8192=VSA Attack), file operation counts (`CreateCount`, `DeleteCount`, `ModCount`, `RenameCount`, `InfectedFilesCount`), data sizes (`ApplicationSizeMB`, `BackupSizeMB`), and client details (`ClientName`, `ClientId`). The connector requires a Commvault Base URL and a valid QSDK Access Token.",
13+
"graphQueriesTableName": "CommvaultAlertsCCF_CL",
14+
"graphQueries": [
15+
{
16+
"metricName": "Total anomaly events received",
17+
"legend": "Commvault Security IQ Events",
18+
"baseQuery": "CommvaultAlertsCCF_CL"
19+
}
20+
],
21+
"sampleQueries": [
22+
{
23+
"description": "Last 10 anomaly events",
24+
"query": "CommvaultAlertsCCF_CL\n| where TimeGenerated > ago(24h)\n| project TimeGenerated, AnomalyType, ClientName, ClientId, CreateCount, DeleteCount, ModCount, RenameCount, InfectedFilesCount, Location\n| sort by TimeGenerated desc\n| limit 10"
25+
},
26+
{
27+
"description": "High-severity anomalies (Ransomware: bit 64, VSA: bit 8192)",
28+
"query": "CommvaultAlertsCCF_CL\n| where TimeGenerated > ago(7d)\n| where binary_and(AnomalyType, 64) == 64 or binary_and(AnomalyType, 8192) == 8192\n| project TimeGenerated, ClientName, AnomalyType, InfectedFilesCount, Location\n| sort by TimeGenerated desc"
29+
},
30+
{
31+
"description": "Clients with the most anomaly events in the last 7 days",
32+
"query": "CommvaultAlertsCCF_CL\n| where TimeGenerated > ago(7d)\n| summarize EventCount = count() by ClientName\n| sort by EventCount desc\n| limit 20"
33+
}
34+
],
35+
"dataTypes": [
36+
{
37+
"name": "CommvaultAlertsCCF_CL",
38+
"lastDataReceivedQuery": "CommvaultAlertsCCF_CL\n| where TimeGenerated > ago(12h)\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
39+
}
40+
],
41+
"connectivityCriteria": [
42+
{
43+
"type": "HasDataConnectors"
44+
}
45+
],
46+
"availability": {
47+
"isPreview": true,
48+
"status": 1
49+
},
50+
"permissions": {
51+
"resourceProvider": [
52+
{
53+
"provider": "Microsoft.OperationalInsights/workspaces",
54+
"permissionsDisplayText": "Read and Write permissions are required.",
55+
"providerDisplayName": "Workspace",
56+
"scope": "Workspace",
57+
"requiredPermissions": {
58+
"write": true,
59+
"read": true,
60+
"delete": true,
61+
"action": false
62+
}
63+
}
64+
],
65+
"customs": [
66+
{
67+
"name": "Commvault API Credentials",
68+
"description": "A Commvault environment Base URL and a valid QSDK Access Token are required to authorize API requests."
69+
}
70+
]
71+
},
72+
"instructionSteps": [
73+
{
74+
"title": "1. Connector Management",
75+
"description": "Manage your Commvault Security IQ connector instances. Each instance connects to one Commvault environment.",
76+
"instructions": [
77+
{
78+
"type": "Markdown",
79+
"parameters": {
80+
"content": "## Commvault Security IQ Connector Instances\n\nThis connector polls the Commvault `/Client/Anomaly` API every 30 minutes and ingests threat anomaly events into the `CommvaultAlertsCCF_CL` table."
81+
}
82+
},
83+
{
84+
"type": "DataConnectorsGrid",
85+
"parameters": {
86+
"mapping": [
87+
{
88+
"columnName": "Environment Endpoint",
89+
"columnValue": "properties.request.apiEndpoint"
90+
},
91+
{
92+
"columnName": "Status",
93+
"columnValue": "properties.connectionState"
94+
}
95+
],
96+
"menuItems": [
97+
"DeleteConnector"
98+
]
99+
}
100+
},
101+
{
102+
"type": "ContextPane",
103+
"parameters": {
104+
"label": "Add Connector",
105+
"title": "Add Commvault Security IQ Connector",
106+
"subtitle": "Connect to a Commvault environment",
107+
"contextPaneType": "DataConnectorsContextPane",
108+
"instructionSteps": [
109+
{
110+
"instructions": [
111+
{
112+
"type": "Markdown",
113+
"parameters": {
114+
"content": "## API Configuration\n\nProvide your Commvault environment endpoint URL and QSDK Access Token."
115+
}
116+
},
117+
{
118+
"type": "Textbox",
119+
"parameters": {
120+
"label": "Commvault Environment Endpoint URL",
121+
"placeholder": "https://your-environment.metallic.io/commandcenter/api",
122+
"type": "text",
123+
"name": "endpointUrl",
124+
"validations": {
125+
"required": true
126+
}
127+
}
128+
},
129+
{
130+
"type": "InfoMessage",
131+
"parameters": {
132+
"text": "Enter the full API base URL of your Commvault environment including the `/commandcenter/api` path (e.g., `https://your-commvault-endpoint/commandcenter/api`). Do **not** include `/Client/Anomaly` — the connector appends this automatically.",
133+
"visible": true,
134+
"inline": false
135+
}
136+
},
137+
{
138+
"type": "Textbox",
139+
"parameters": {
140+
"label": "QSDK Access Token",
141+
"placeholder": "Enter your Commvault QSDK Access Token",
142+
"type": "password",
143+
"name": "qsdkToken",
144+
"validations": {
145+
"required": true
146+
}
147+
}
148+
},
149+
{
150+
"type": "InfoMessage",
151+
"parameters": {
152+
"text": "The QSDK Token is sent as a `Bearer` token in the `Authorization` header. Generate this token from the Commvault Command Center under **Security > API Tokens**.",
153+
"visible": true,
154+
"inline": false
155+
}
156+
},
157+
{
158+
"type": "InfoMessage",
159+
"parameters": {
160+
"text": "**Data Collection Schedule**: The connector polls for new anomaly events every 30 minutes.",
161+
"visible": true,
162+
"inline": true
163+
}
164+
}
165+
]
166+
}
167+
]
168+
}
169+
}
170+
]
171+
}
172+
]
173+
}
174+
}
175+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"name": "CommvaultSecurityIQDCR",
3+
"apiVersion": "2023-04-01-preview",
4+
"type": "Microsoft.Insights/dataCollectionRules",
5+
"location": "{{location}}",
6+
"properties": {
7+
"dataCollectionEndpointId": "{{dataCollectionEndpointId}}",
8+
"streamDeclarations": {
9+
"Custom-CommvaultAlertsCCF_CL": {
10+
"columns": [
11+
{
12+
"name": "refTime",
13+
"type": "long",
14+
"description": "Epoch timestamp (seconds) of the anomaly event from Commvault."
15+
},
16+
{
17+
"name": "anomalyType",
18+
"type": "int",
19+
"description": "Bitfield integer identifying the anomaly type(s). Bit 64=Ransomware, Bit 8192=VSA Attack."
20+
},
21+
{
22+
"name": "createCount",
23+
"type": "int"
24+
},
25+
{
26+
"name": "deleteCount",
27+
"type": "int"
28+
},
29+
{
30+
"name": "modCount",
31+
"type": "int"
32+
},
33+
{
34+
"name": "renameCount",
35+
"type": "int"
36+
},
37+
{
38+
"name": "infectedFilesCount",
39+
"type": "int"
40+
},
41+
{
42+
"name": "location",
43+
"type": "string"
44+
},
45+
{
46+
"name": "client",
47+
"type": "dynamic",
48+
"description": "Nested object containing clientName and clientId."
49+
}
50+
]
51+
}
52+
},
53+
"destinations": {
54+
"logAnalytics": [
55+
{
56+
"workspaceResourceId": "{{workspaceResourceId}}",
57+
"name": "clv2ws1"
58+
}
59+
]
60+
},
61+
"dataFlows": [
62+
{
63+
"streams": [
64+
"Custom-CommvaultAlertsCCF_CL"
65+
],
66+
"destinations": [
67+
"clv2ws1"
68+
],
69+
"outputStream": "Custom-CommvaultAlertsCCF_CL",
70+
"transformKql": "source | extend TimeGenerated = iff(isnull(refTime), now(), datetime(1970-01-01) + tolong(refTime) * 1s) , RefTime = tolong(refTime) , AnomalyType = toint(anomalyType) , CreateCount = toint(createCount) , DeleteCount = toint(deleteCount) , ModCount = toint(modCount) , RenameCount = toint(renameCount) , InfectedFilesCount = toint(infectedFilesCount) , Location = tostring(location) , ClientName = tostring(client.clientName) , ClientId = toint(client.clientId) | project TimeGenerated , RefTime , AnomalyType , CreateCount , DeleteCount , ModCount , RenameCount , InfectedFilesCount , Location , ClientName , ClientId"
71+
}
72+
]
73+
}
74+
}

0 commit comments

Comments
 (0)