{
  "name": "VectraRUXConnector",
  "apiVersion": "2022-09-01-preview",
  "type": "Microsoft.SecurityInsights/dataConnectorDefinitions",
  "location": "{{location}}",
  "kind": "Customizable",
  "properties": {
    "connectorUiConfig": {
      "id": "VectraRUXConnector",
      "title": "Vectra RUX Security Data Connector (via Codeless Connector Framework)",
      "publisher": "Vectra AI",
      "descriptionMarkdown": "The [Vectra RUX](https://www.vectra.ai/) data connector enables you to ingest security data from the Vectra AI platform into Microsoft Sentinel through the REST API using the Codeless Connector Framework (CCF). This connector supports 3 data streams using OAuth2 client credentials:<br>- **Detections**: Security detections, filtered by triaged status.<br>- **Lockdown**: Entity isolation and containment status. Live state captured every 5 minutes.<br>- **Entities**: Host and account entities with scoring, assignment, and enrichment data, incrementally ingested ordered by last modification time.<br><br>The connector is built on the Microsoft Sentinel Codeless Connector Platform and supports DCR-based [ingestion time transformations](https://docs.microsoft.com/azure/azure-monitor/logs/custom-logs-overview) for optimized query performance.",
      "graphQueriesTableName": "Detections_Data_CCF_CL",
      "graphQueries": [
        {
          "metricName": "Total Detections received",
          "legend": "Vectra Detections",
          "baseQuery": "Detections_Data_CCF_CL"
        },
        {
          "metricName": "Lockdown actions",
          "legend": "Vectra Lockdown",
          "baseQuery": "Lockdown_Data_CCF_CL"
        },
        {
          "metricName": "Total Entities received",
          "legend": "Vectra Entities",
          "baseQuery": "Entities_Data_CCF_CL"
        }
      ],
      "sampleQueries": [
        {
          "description": "Get sample of Vectra Detections",
          "query": "Detections_Data_CCF_CL\n| take 10"
        },
        {
          "description": "View recent high-severity detections",
          "query": "Detections_Data_CCF_CL\n| where severity in (5, 4)\n| where TimeGenerated > ago(24h)\n| sort by TimeGenerated desc"
        },
        {
          "description": "View current and recent lockdown actions",
          "query": "Lockdown_Data_CCF_CL\n| where TimeGenerated > ago(24h)\n| sort by TimeGenerated desc"
        },
        {
          "description": "View recently modified entities",
          "query": "Entities_Data_CCF_CL\n| where TimeGenerated > ago(24h)\n| sort by TimeGenerated desc"
        }
      ],
      "dataTypes": [
        {
          "name": "Detections_Data_CCF_CL",
          "lastDataReceivedQuery": "Detections_Data_CCF_CL\n| where TimeGenerated > ago(12h) | summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
        },
        {
          "name": "Lockdown_Data_CCF_CL",
          "lastDataReceivedQuery": "Lockdown_Data_CCF_CL\n| where TimeGenerated > ago(12h) | summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
        },
        {
          "name": "Entities_Data_CCF_CL",
          "lastDataReceivedQuery": "Entities_Data_CCF_CL\n| where TimeGenerated > ago(12h) | summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
        }
      ],
      "connectivityCriteria": [
        {
          "type": "HasDataConnectors"
        }
      ],
      "availability": {
        "isPreview": true,
        "status": 1
      },
      "permissions": {
        "resourceProvider": [
          {
            "provider": "Microsoft.OperationalInsights/workspaces",
            "permissionsDisplayText": "Read and Write permissions are required.",
            "providerDisplayName": "Workspace",
            "scope": "Workspace",
            "requiredPermissions": {
              "write": true,
              "read": true,
              "delete": true,
              "action": false
            }
          }
        ],
        "customs": [
          {
            "name": "Vectra RUX API access",
            "description": "Access to Vectra RUX API with appropriate permissions for each data stream is required."
          }
        ]
      },
      "instructionSteps": [
        {
          "title": "1. Configure Vectra RUX Connection",
          "description": "Connect to Vectra RUX and select data stream",
          "instructions": [
            {
              "type": "Markdown",
              "parameters": {
                "content": "## Vectra RUX Data Connector Configuration\n\nConfigure your Vectra RUX connection and select the data stream you want to collect. Each stream provides different types of security data from your Vectra AI platform."
              }
            },
            {
              "type": "DataConnectorsGrid",
              "parameters": {
                "mapping": [
                  {
                    "columnName": "Alias",
                    "columnValue": "properties.addOnAttributes.alias"
                  },
                  {
                    "columnName": "Stream Type",
                    "columnValue": "properties.addOnAttributes.streamType"
                  },
                  {
                    "columnName": "API Base URL",
                    "columnValue": "properties.addOnAttributes.apiUrl"
                  }
                ],
                "menuItems": [
                  "DeleteConnector"
                ]
              }
            },
            {
              "type": "ContextPane",
              "parameters": {
                "label": "Add Connection",
                "title": "Add Vectra RUX Data Stream Connection",
                "subtitle": "Configure Vectra RUX API connection and select data stream",
                "contextPaneType": "DataConnectorsContextPane",
                "instructionSteps": [
                  {
                    "title": "Base Configuration",
                    "description": "Configure your Vectra RUX API connection",
                    "instructions": [
                      {
                        "type": "Markdown",
                        "parameters": {
                          "content": "### Base API Configuration"
                        }
                      },
                      {
                        "type": "Textbox",
                        "parameters": {
                          "label": "Connection Alias",
                          "placeholder": "Production Vectra",
                          "type": "text",
                          "name": "alias",
                          "validations": {
                            "required": false
                          }
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "Enter a name to identify this Vectra instance — for example, 'Vectra-Prod' or 'Vectra-Dev'. Use the same alias for all data streams from the same Vectra instance. Use a different alias only when connecting to a separate Vectra instance. Warning: deploying the same stream type with the same alias will overwrite the existing connection for that stream.",
                          "visible": true,
                          "inline": true
                        }
                      },
                      {
                        "type": "Textbox",
                        "parameters": {
                          "label": "Vectra API Base URL",
                          "placeholder": "https://tenant.region.portal.vectra.ai",
                          "type": "url",
                          "name": "vectraApiUrl",
                          "validations": {
                            "required": false
                          }
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "Enter the base URL of your Vectra RUX instance without trailing slash (e.g., https://tenant.region.portal.vectra.ai). **HTTPS is required** — HTTP URLs will transmit credentials in cleartext.",
                          "visible": true,
                          "inline": true
                        }
                      }
                    ]
                  },
                  {
                    "title": "OAuth2 Credentials",
                    "description": "Configure OAuth2 credentials for API access",
                    "instructions": [
                      {
                        "type": "Markdown",
                        "parameters": {
                          "content": "### OAuth2 Client Credentials"
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "The Vectra RUX connector uses OAuth2 client credentials flow to authenticate with all API endpoints. These credentials provide access to the selected data stream.",
                          "visible": true,
                          "inline": false
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "**Important**: To avoid API rate limiting (HTTP 429 errors) when requesting OAuth tokens, create a separate API client in Vectra for each data stream connection and wait one minute before attempting to create additional connections. Assign each API client the **Read-Only** role to apply the principle of least privilege. For instructions on creating API clients, see the [Vectra API Client Setup Guide](https://docs.vectra.ai/configuration/access/api-rux/rux-api-postman-quick-start-guide).",
                          "visible": true,
                          "inline": true
                        }
                      },
                      {
                        "type": "Textbox",
                        "parameters": {
                          "label": "Client ID",
                          "placeholder": "Enter OAuth2 Client ID",
                          "type": "text",
                          "name": "clientId",
                          "validations": {
                            "required": false
                          }
                        }
                      },
                      {
                        "type": "Textbox",
                        "parameters": {
                          "label": "Client Secret",
                          "placeholder": "Enter OAuth2 Client Secret",
                          "type": "password",
                          "name": "clientSecret",
                          "validations": {
                            "required": false
                          }
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "**Best Practice**: Create dedicated API clients in Vectra RUX for each stream (e.g., 'Sentinel-Detections', 'Sentinel-Entities', 'Sentinel-Lockdown') and assign each the role of **Read-Only** to apply the principle of least privilege.",
                          "visible": true,
                          "inline": false
                        }
                      }
                    ]
                  },
                  {
                    "title": "Data Stream Selection",
                    "description": "Select which Vectra RUX data stream to collect",
                    "instructions": [
                      {
                        "type": "Markdown",
                        "parameters": {
                          "content": "### Data Stream Configuration"
                        }
                      },
                      {
                        "type": "Dropdown",
                        "parameters": {
                          "label": "Data Stream",
                          "name": "selectedStream",
                          "options": [
                            {
                              "key": "detections",
                              "text": "Detections - Security detections"
                            },
                            {
                              "key": "entities",
                              "text": "Entities - Host and account entities with scoring and assignment data"
                            },
                            {
                              "key": "lockdown",
                              "text": "Lockdown - Security lockdown and containment actions"
                            }
                          ],
                          "placeholder": "Select data stream to collect...",
                          "isMultiSelect": false,
                          "defaultAllSelected": false,
                          "required": true
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "**Stream Details:**\r\n\r\n- **Detections**: Security detections. Uses checkpoint-based polling (`next_checkpoint` cursor) every 5 minutes.\r\n- **Entities**: Host and account entities with scoring, assignment, and privilege data. Polls every 10 minutes using `last_modified_timestamp_gte` sliding window — each poll requests only entities modified since the previous poll window.\r\n- **Lockdown**: Entity isolation and containment status. Live state captured every 5 minutes.\r\n",
                          "visible": true,
                          "inline": false
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "**Detections Starting Checkpoint — Required for New Installations**\n\n⚠️ **Detections stream only** —  Enter 'Vectra' text if you are adding a Lockdown or Entities connection.\n\nIf adding a Detections connection, this field is critical. Leaving it empty will cause the poller to start from the oldest available event in your Vectra history, which can take many hours or days to catch up on large deployments and will flood your Log Analytics workspace with historical data.\n\nBefore creating a Detections connection, run the following API call against your Vectra instance to obtain the current cursor value:\n\n`GET <vectraApiUrl>/api/v3.5/events/detections?limit=1&ordering=-event_timestamp` → copy the `next_checkpoint` value from the response",
                          "visible": true,
                          "inline": false
                        }
                      },
                      {
                        "type": "InfoMessage",
                        "parameters": {
                          "text": "**Detections Starting Checkpoint - Required for Upgrading from an existing deployment** Run this query in your Log Analytics workspace to get the current checkpoint and avoid re-ingesting historical data:\n\n`Detections_Data_CL | summarize checkpoint = max(id)` (If this is the first deployment to an existing environment) or `Detections_Data_CCF_CL | summarize checkpoint = max(id)` (if this is a RE-DEPLOYMENT of the CCF connector)\n\nPaste the returned value into the field below. Enter '0' for a fresh install with no existing Detections data.",
                          "visible": true,
                          "inline": false
                        }
                      },
                      {
                        "type": "Textbox",
                        "parameters": {
                          "label": "Detections Starting Checkpoint — Enter 'Vectra' as text for adding Lockdown or Entities data",
                          "placeholder": "Paste next_checkpoint from GET /api/v3.5/events/detections?limit=1&ordering=-event_timestamp",
                          "type": "text",
                          "name": "detectionsStartingCheckpoint",
                          "validations": {
                            "required": true
                          }
                        }
                      }
                    ]
                  }
                ]
              }
            },
            {
              "type": "InfoMessage",
              "parameters": {
                "text": "**Note**: After adding a connection, the Detections stream polls every 5 minutes using a persistent checkpoint cursor (`PersistentToken`) — position-based, not time-based. The cursor survives pod restarts and long pagination runs; no events will be silently skipped due to clock drift or slow pages. **First poll seeding**: Provide the `detectionsStartingCheckpoint` value when creating the connection to start ingestion at your current event position rather than from the beginning of history.",
                "visible": true,
                "inline": true
              }
            },
            {
              "type": "InfoMessage",
              "parameters": {
                "text": "**Troubleshooting Rate Limits (HTTP 429 Errors) when adding connections**:\n- **Root Cause**: Vectra RUX limits API requests to prevent abuse\n- **Solution**: Create a separate API client in Vectra for each data stream connection\n- **Verification**: Check that each connector instance uses different `clientId` credentials\n- **Deployment Strategy**: Stagger connection creation by at least one minute when adding multiple streams simultaneously to prevent OAuth2 request collisions",
                "visible": true,
                "inline": false
              }
            }
          ]
        },
        {
          "title": "2. Monitor and Validate Data Collection",
          "description": "Monitor data ingestion and validate connectivity",
          "instructions": [
            {
              "type": "Markdown",
              "parameters": {
                "content": "### Post-Configuration Steps\n\n1. **Monitor Connection Status**: Check the connector status in the Data connectors page.\n2. **Validate Data Flow**: Use the sample queries provided to verify data is being collected.\n3. **Review Connector Health (Optional)**: The `SentinelHealth` table provides per-poll-cycle status for each data stream, including failure reasons for authentication, network, and ingestion errors. It is not enabled by default.\n\n   **To enable**: Go to **Microsoft Sentinel → Settings → Settings tab → Health and Audit** and toggle on health monitoring for data connectors. See [Enable health monitoring for Microsoft Sentinel](https://learn.microsoft.com/en-us/azure/sentinel/enable-monitoring) for full instructions.\n\n   **Once enabled**, run the following query to check connector poll status:\n\n   `SentinelHealth | where TimeGenerated > ago(24h) | where SentinelResourceType == \"Data connector\" | project TimeGenerated, SentinelResourceName, Status, Description, Reason | order by TimeGenerated desc`\n\n### Stream-Specific Notes\n\n- **Detections**: Filters out triaged detections by default (`include_triaged=false`)."
              }
            },
            {
              "type": "InfoMessage",
              "parameters": {
                "text": "**PersistentToken Checkpoint Mode (Detections)**\n\nThe Detections poller uses `PersistentToken` — the `next_checkpoint` value returned by the Vectra API is stored by CCF and passed back as `from=<checkpoint>` on the next poll cycle. This is position-based (monotonic `id`-based), not time-based, so slow pagination or pod restarts cannot cause silent data gaps.\n\n**Cold-start behaviour**: On the very first poll after deployment, CCF sends `from=<detectionsStartingCheckpoint>` as the starting cursor. Ingestion begins at this cursor position, ensuring no historical backlog is ingested. Once the first poll completes, PersistentToken persists the returned `next_checkpoint` and all subsequent polls use the stored value automatically.",
                "visible": true,
                "inline": false
              }
            }
          ]
        }
      ]
    }
  }
}