From 2a1ca1d252b3ef687f1ae96aeb8dd5a4b38c1cb6 Mon Sep 17 00:00:00 2001 From: nikhildubey-trend Date: Wed, 10 Jun 2026 16:40:55 +0530 Subject: [PATCH] TrendAI sentinel data connector based on CCF --- Solutions/TrendAI Vision One/CODEOWNERS | 12 + .../TrendAI Vision One/CODE_OF_CONDUCT.md | 128 +++ Solutions/TrendAI Vision One/CONTRIBUTING.md | 116 +++ Solutions/TrendAI Vision One/LICENSE | 21 + Solutions/TrendAI Vision One/README.md | 370 +++++++ Solutions/TrendAI Vision One/SECURITY.md | 58 ++ .../assets/trendai-logo.svg | 4 + .../TrendAI Vision One/docs/01-concepts.md | 170 ++++ .../TrendAI Vision One/docs/02-permissions.md | 152 +++ .../TrendAI Vision One/docs/03-deployment.md | 178 ++++ .../docs/04-using-the-connector.md | 218 +++++ .../TrendAI Vision One/docs/05-migration.md | 222 +++++ .../docs/06-troubleshooting.md | 100 ++ Solutions/TrendAI Vision One/docs/README.md | 39 + .../docs/internal/test-deploy.md | 93 ++ .../functions/Parser-OAT.kql | 36 + .../functions/Parser-Workbench.kql | 246 +++++ .../scripts/publish-templates.sh | 74 ++ .../templates/ARCHITECTURE.md | 402 ++++++++ .../templates/legacy/README.md | 35 + .../arm-template-oat-compatibleSchema.json | 926 ++++++++++++++++++ .../legacy/arm-template-oat-newSchema.json | 534 ++++++++++ ...m-template-workbench-compatibleSchema.json | 436 +++++++++ .../arm-template-workbench-newSchema.json | 546 +++++++++++ .../legacy/deploy-parser-function-oat.json | 48 + .../legacy/deploy-parser-function.json | 48 + .../oat/components/connector-definition.json | 111 +++ .../oat/components/data-connector.json | 114 +++ .../templates/oat/components/dce.json | 39 + .../templates/oat/components/dcr.json | 125 +++ .../oat/components/parser-function.json | 52 + .../oat/components/sentinel-solution.json | 39 + .../templates/oat/components/table.json | 196 ++++ .../templates/oat/createUiDefinition.json | 149 +++ .../templates/oat/mainTemplate.json | 231 +++++ .../workbench/components/analytic-rule.json | 141 +++ .../components/connector-definition.json | 190 ++++ .../workbench/components/data-connector.json | 111 +++ .../templates/workbench/components/dce.json | 43 + .../templates/workbench/components/dcr.json | 96 ++ .../workbench/components/parser-function.json | 52 + .../components/sentinel-solution.json | 45 + .../templates/workbench/components/table.json | 103 ++ .../workbench/components/workbook.json | 48 + .../workbench/createUiDefinition.json | 152 +++ .../templates/workbench/mainTemplate.json | 370 +++++++ 46 files changed, 7619 insertions(+) create mode 100644 Solutions/TrendAI Vision One/CODEOWNERS create mode 100644 Solutions/TrendAI Vision One/CODE_OF_CONDUCT.md create mode 100644 Solutions/TrendAI Vision One/CONTRIBUTING.md create mode 100644 Solutions/TrendAI Vision One/LICENSE create mode 100644 Solutions/TrendAI Vision One/README.md create mode 100644 Solutions/TrendAI Vision One/SECURITY.md create mode 100644 Solutions/TrendAI Vision One/assets/trendai-logo.svg create mode 100644 Solutions/TrendAI Vision One/docs/01-concepts.md create mode 100644 Solutions/TrendAI Vision One/docs/02-permissions.md create mode 100644 Solutions/TrendAI Vision One/docs/03-deployment.md create mode 100644 Solutions/TrendAI Vision One/docs/04-using-the-connector.md create mode 100644 Solutions/TrendAI Vision One/docs/05-migration.md create mode 100644 Solutions/TrendAI Vision One/docs/06-troubleshooting.md create mode 100644 Solutions/TrendAI Vision One/docs/README.md create mode 100644 Solutions/TrendAI Vision One/docs/internal/test-deploy.md create mode 100644 Solutions/TrendAI Vision One/functions/Parser-OAT.kql create mode 100644 Solutions/TrendAI Vision One/functions/Parser-Workbench.kql create mode 100755 Solutions/TrendAI Vision One/scripts/publish-templates.sh create mode 100644 Solutions/TrendAI Vision One/templates/ARCHITECTURE.md create mode 100644 Solutions/TrendAI Vision One/templates/legacy/README.md create mode 100644 Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-compatibleSchema.json create mode 100644 Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-newSchema.json create mode 100644 Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-compatibleSchema.json create mode 100644 Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-newSchema.json create mode 100644 Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function-oat.json create mode 100644 Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/connector-definition.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/data-connector.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/dce.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/dcr.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/parser-function.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/sentinel-solution.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/components/table.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/createUiDefinition.json create mode 100644 Solutions/TrendAI Vision One/templates/oat/mainTemplate.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/analytic-rule.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/connector-definition.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/data-connector.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/dce.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/dcr.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/parser-function.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/sentinel-solution.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/table.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/components/workbook.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/createUiDefinition.json create mode 100644 Solutions/TrendAI Vision One/templates/workbench/mainTemplate.json diff --git a/Solutions/TrendAI Vision One/CODEOWNERS b/Solutions/TrendAI Vision One/CODEOWNERS new file mode 100644 index 00000000000..87b54fd5e09 --- /dev/null +++ b/Solutions/TrendAI Vision One/CODEOWNERS @@ -0,0 +1,12 @@ +# Code owners for this repository. +# +# Every pull request that touches a path listed below will automatically +# request review from the matching owners. When branch protection is +# enabled on `main` with "Require review from Code Owners", these owners +# must approve before the PR can merge. +# +# Replace @trendmicro/mxdr-team with the real GitHub team handle before +# enabling the corresponding branch protection rule. +# Syntax: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-security/customizing-your-repository/about-code-owners + +* @trendmicro/mxdr-team diff --git a/Solutions/TrendAI Vision One/CODE_OF_CONDUCT.md b/Solutions/TrendAI Vision One/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..bdb820ddb8f --- /dev/null +++ b/Solutions/TrendAI Vision One/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +opensource@github.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. \ No newline at end of file diff --git a/Solutions/TrendAI Vision One/CONTRIBUTING.md b/Solutions/TrendAI Vision One/CONTRIBUTING.md new file mode 100644 index 00000000000..ac99526924f --- /dev/null +++ b/Solutions/TrendAI Vision One/CONTRIBUTING.md @@ -0,0 +1,116 @@ +# Contributing + +We're so glad you're thinking about contributing to the **Trend Vision One – Microsoft Sentinel Data Connectors** repository! This repo contains production ARM templates that ship Trend Vision One security data into Microsoft Sentinel via the Codeless Connector Platform (CCP). Because every change can affect a live deployment in someone's Azure tenant, we ask contributors to keep templates deployable and review-friendly. + +We welcome contributions from everyone and are particularly looking for help in the following areas: + +- **Fixing template or documentation errors** — typos, broken parameter references, outdated screenshots, incorrect KQL examples, or missing fields in `mainTemplate.json` / `createUiDefinition.json`. +- **Adding new features** — additional Trend Vision One data sources, new parser functions, improved data-collection-rule transforms, or richer connector UI. +- **Improving existing documentation** — clearer deployment walkthroughs, better troubleshooting steps, more useful sample KQL queries. + +## Code of Conduct + +This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. + +## Reporting Issues + +Please report issues in the [GitHub issue tracker](https://github.com/trendmicro/trendai-sentinel-ccf-data-connector/issues) using one of the provided templates. Include as much detail as possible — connector (Workbench / OAT), deploy region, commit SHA, Azure portal error output, and any relevant KQL — so we can reproduce the problem. + +> **Security vulnerabilities** must **not** be filed as public issues. See [SECURITY.md](SECURITY.md) for the private reporting process. + +## Contributing Code + +1. **Fork the repository.** Click the *Fork* button at the top right of the repo page and clone your fork locally. +2. **Create a branch.** Use a descriptive name, e.g. `fix/oat-dcr-transform` or `feat/workbench-parser-iocs`. +3. **Make your changes.** Edit templates, parser functions, or documentation. Keep changes focused — one logical change per PR. +4. **Validate locally** before pushing (see below). +5. **Commit your changes** with a clear message describing the *why*, not just the *what*. +6. **Push to your fork** and open a pull request against `main` using the [PR template](.github/PULL_REQUEST_TEMPLATE.md). + +## Local Validation + +Before opening a pull request, please run these checks: + +### JSON syntax + +```bash +find templates -name "*.json" -not -path "*/legacy/*" -print0 \ + | xargs -0 -n1 jq empty +``` + +Every file must parse cleanly. + +### ARM template structure + +For changes to `mainTemplate.json` or any file under `templates/*/components/`, confirm the required top-level fields exist: + +```bash +jq -e '.["$schema"] and .contentVersion and .resources' \ + templates/workbench/mainTemplate.json +``` + +### Azure validation (recommended for template changes) + +If you have an Azure subscription with a Sentinel-enabled workspace, validate the deployment without actually creating resources: + +```bash +az deployment group validate \ + --resource-group \ + --template-file templates/workbench/mainTemplate.json \ + --parameters workspace= trendaiRegion=US +``` + +### End-to-end deployment + +For non-trivial template changes, deploy to a test workspace and confirm data ingestion before requesting review. Note in the PR description which workspace/region you tested against. + +## Secure Contributor Setup + +A few one-time settings on your GitHub account make every contribution +safer for you and for the people who deploy this connector. + +### Sign your commits + +We strongly recommend signing your commits with **GPG** or **SSH**. Signed +commits show a green *Verified* badge on GitHub and make it harder for +someone to impersonate you. See GitHub's guide: +[About commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification). + +Quick start (SSH signing, Git 2.34+): + +```bash +git config --global gpg.format ssh +git config --global user.signingkey ~/.ssh/id_ed25519.pub +git config --global commit.gpgsign true +``` + +Then add the **same** SSH public key on GitHub under +*Settings → SSH and GPG keys* as a **Signing key** (not just an auth key). + +### Use short-lived Personal Access Tokens + +If you authenticate with HTTPS + a Personal Access Token, please set an +**expiration date** on the token (90 days or less is a good default). +Long-lived tokens are a top source of leaked credentials. Better still, +use SSH or the GitHub CLI's OAuth flow. + +## Style Guidelines + +- **ARM JSON:** 2-space indentation, trailing newline. Keep `apiVersion` values consistent across components. +- **Parameter names:** camelCase (matches existing templates). +- **KQL:** Format multi-line queries with one clause per line; align `|` operators. +- **Documentation:** Markdown headings use sentence case; code fences specify the language. + +## Pull Request Review + +- A maintainer will review your PR within a few business days. +- Address review feedback in additional commits — don't force-push during active review. +- Once approved, a maintainer will squash-merge to `main`. + +## Contact + +If you have questions about contributing, open a [GitHub discussion](https://github.com/trendmicro/trendai-sentinel-ccf-data-connector/discussions) or contact us at `alloftrendgithubenterpriseadmin@trendmicro.com`. + +## Acknowledgements + +Thank you to everyone who has helped improve these connectors. Every typo fix, parameter tweak, and parser improvement makes the project more useful for the Sentinel community. diff --git a/Solutions/TrendAI Vision One/LICENSE b/Solutions/TrendAI Vision One/LICENSE new file mode 100644 index 00000000000..b4bc6afe1c0 --- /dev/null +++ b/Solutions/TrendAI Vision One/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Trend Micro Incorporated + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Solutions/TrendAI Vision One/README.md b/Solutions/TrendAI Vision One/README.md new file mode 100644 index 00000000000..d637234f947 --- /dev/null +++ b/Solutions/TrendAI Vision One/README.md @@ -0,0 +1,370 @@ +# Trend Vision One - Microsoft Sentinel Data Connectors + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) + +**Workbench Alerts**   [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FcreateUiDefinition.json) [![Deploy to Azure US Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FcreateUiDefinition.json) + +**OAT (Observed Attack Techniques)**   [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FcreateUiDefinition.json) [![Deploy to Azure US Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FcreateUiDefinition.json) + +### Test Deploy (Azure Storage-hosted, while repo is private) + +Templates served from a public Azure Blob container so the portal can fetch them without GitHub auth. Remove once the repo goes public. + +**Before clicking the buttons below, publish the latest templates to the blob container** so the deploy URLs serve current code. + +**One-time setup** (per developer): + +```bash +# 1. Install Azure CLI if you don't have it +# macOS: brew install azure-cli +# Linux: https://learn.microsoft.com/cli/azure/install-azure-cli-linux + +# 2. Log in and select the subscription that owns the trendaiccf45 storage account +az login +az account set --subscription "" +``` + +Required access: at least **Contributor** (or **Storage Account Key Operator Service Role**) on the `trendaiccf45` storage account, so `az storage account keys list` works. If you only have data-plane access, use a SAS token instead — see [scripts/publish-templates.sh](scripts/publish-templates.sh). + +**Each time you change templates**, publish them: + +```bash +export AZURE_STORAGE_KEY="$(az storage account keys list \ + --account-name trendaiccf45 \ + --query '[0].value' -o tsv)" + +./scripts/publish-templates.sh +``` + +The script stages `templates/`, rewrites the nested `baseUrl` from the GitHub raw URL to the blob URL, and uploads to `trendaiccf45/arm-templates/`. + +**Workbench Alerts**   [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Ftrendaiccf45.blob.core.windows.net%2Farm-templates%2Fworkbench%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Ftrendaiccf45.blob.core.windows.net%2Farm-templates%2Fworkbench%2FcreateUiDefinition.json) + +**OAT (Observed Attack Techniques)**   [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Ftrendaiccf45.blob.core.windows.net%2Farm-templates%2Foat%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Ftrendaiccf45.blob.core.windows.net%2Farm-templates%2Foat%2FcreateUiDefinition.json) + +Production-ready data connectors for ingesting **Trend Vision One** security data into **Microsoft Sentinel** using Azure's Codeless Connector Platform (CCP). + +## 🚀 Quick Deploy + +Choose the connector you need and click the Deploy button above: + +| Connector | Description | Data Volume | Deploy | +|-----------|-------------|-------------|--------| +| **Workbench Alerts** | Security incidents, investigations, and alerts with IOC extraction | Medium | [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Fworkbench%2FcreateUiDefinition.json) | +| **OAT (Observed Attack Techniques)** | MITRE ATT&CK mapped detections with full process trees | High | [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FmainTemplate.json/createUIDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2Ftrendmicro%2Ftrendai-sentinel-ccf-data-connector%2Fmain%2Ftemplates%2Foat%2FcreateUiDefinition.json) | + +## 📋 Prerequisites + +Before deploying, ensure you have: + +- ✅ **Azure Subscription** with Owner or Contributor role +- ✅ **Log Analytics Workspace** with Microsoft Sentinel enabled (or workspace will be enabled during deployment) +- ✅ **Trend Vision One API Token** with 'SIEM' role permissions + +### Getting Your API Token + +1. Log in to **Trend Vision One Console** +2. Navigate to **Administration → API Keys** +3. Click **Generate New API Key** +4. Select role: **SIEM** or **Workbench** +5. Copy the token (you'll need it after deployment) + +## 🎯 Deployment Process + +### Step 1: Click Deploy Button + +Click one of the blue/green Deploy buttons above + +### Step 2: Fill Azure Portal Form + +The custom deployment UI will appear with: +- **Subscription** - Select your Azure subscription +- **Resource Group** - Select or create new +- **Workspace** - Dropdown of your Sentinel workspaces +- **Region** - Your Trend Vision One region (US, UK, SG, CA, JP) + +### Step 3: Deploy Resources + +Azure will automatically deploy: +1. Microsoft Sentinel solution (if not enabled) +2. Custom log table (TrendMicro_XDR_WORKBENCH_CL or TrendMicro_XDR_OAT_CL) +3. Data Collection Endpoint (DCE) +4. Data Collection Rule (DCR) with data transformation +5. Connector definition in Sentinel portal +6. Parser function (Workbench: `TrendMicroWorkbench_Complete`, OAT: `TrendMicroOAT_Complete`) +7. Analytic rule template (disabled by default) +8. Workbook dashboard for monitoring + +⏱️ **Deployment time**: 3-5 minutes + +### Step 4: Connect the Data Source + +After deployment completes: + +1. Navigate to **Microsoft Sentinel → Data connectors** +2. Search for **"Trend Vision One - Workbench"** or **"Trend Vision One - OAT"** +3. Click **Open connector page** +4. Enter your API token (include `Bearer ` prefix) +5. Click **Connect** + +🎉 **Data will start flowing in 5-10 minutes!** + +### Step 5: Enable Analytic Rules (Optional) + +Each connector includes an **Analytic Rule** that automatically creates incidents: + +1. Navigate to **Microsoft Sentinel → Analytics** +2. Search for **"Trend Vision One"** +3. Find the rule: + - **Workbench**: "Create Incident for Workbench Alerts" + - **OAT**: "Create Incident for High-Risk OAT Detections" +4. Click the rule → **Edit** → **Enable** → **Save** + +**What it does:** +- Runs every 5 minutes +- Creates incidents with mapped entities (Account, File, Process, IP, Host) +- Groups related alerts by WorkbenchID/EventID +- Adds custom details for investigations + +### Step 6: View Dashboards (Optional) + +Each connector includes a **Workbook** dashboard: + +1. Navigate to **Microsoft Sentinel → Workbooks** +2. Click **My workbooks** tab +3. Find: + - **Workbench**: "TrendVisionOneWorkbenchOverview" + - **OAT**: "TrendVisionOneOATOverview" +4. Click **View saved workbook** + +**Visualizations include:** +- Alert/Detection trends over time +- Severity/Risk level distribution +- Top affected hosts/endpoints +- MITRE ATT&CK tactics and techniques (OAT only) +- Detection model usage (Workbench only) + +## 📊 Verify Data Ingestion + +### Workbench Alerts + +```kql +TrendMicro_XDR_WORKBENCH_CL +| where TimeGenerated > ago(1h) +| project TimeGenerated, workbenchId_s, severity_s, workbenchName_s +| take 10 +``` + +### OAT Detections + +```kql +TrendMicro_XDR_OAT_CL +| where TimeGenerated > ago(1h) +| project TimeGenerated, entityType_s, detail_endpointHostName_s, detail_filterRiskLevel_s +| take 10 +``` + +## 🏗️ Architecture + +This solution follows Microsoft's recommended **modular architecture** pattern: + +``` +mainTemplate.json (Orchestrator) + ├─> sentinel-solution.json # Enables Sentinel + ├─> table.json # Creates custom table + ├─> dce.json # Data Collection Endpoint + ├─> dcr.json # Data Collection Rule (transforms data) + ├─> connector-definition.json # Connector UI in portal + ├─> parser-function.json # KQL parser (Workbench + OAT; universal old+new) + ├─> analytic-rule.json # Incident creation rule (disabled) + └─> workbook.json # Monitoring dashboard +``` + +**Benefits:** +- ✅ Single-click deployment via Azure Portal +- ✅ Each component can be updated independently +- ✅ Easy to troubleshoot and maintain +- ✅ Follows Microsoft Sentinel best practices + +## 📖 Data Schemas + +### Workbench Alerts (56 columns) + +| Category | Fields | +|----------|--------| +| **Core** | workbenchId_s, severity_s, investigationStatus_s, alertProvider_s | +| **IOCs** | FileName_s, FileHashValue_s, IPAddress, DomainName_s, URL_s | +| **Entities** | HostHostName_s, UserAccountName_s, MailboxPrimaryAddress_s | +| **Dynamic** | indicators, entities, matchedRules (for advanced parsing) | + +### OAT Detections (139 columns) + +| Category | Fields | +|----------|--------| +| **Core** | entityType_s, entityName_s, detectionTime_t | +| **Endpoint** | endpoint_name_s, endpoint_guid_g, endpoint_ips_s | +| **Process** | detail_processCmd_s, detail_processFileHashSha256_s, detail_processPid_d | +| **Parent** | detail_parentCmd_s, detail_parentFileHashSha256_s, detail_parentName_s | +| **Network** | detail_src_s, detail_dst_s, detail_dpt_d, detail_spt_d | +| **File** | detail_fileName_s, detail_fileHash_s, detail_filePathName_s | + +## 🔍 Sample Queries + +### Workbench: High Severity Alerts with File IOCs + +```kql +TrendMicroWorkbench_Complete() +| where severity_s in ("high", "critical") +| where isnotempty(FileHashValue_s) +| project TimeGenerated, workbenchName_s, FileName_s, FileHashValue_s, HostHostName_s +``` + +### OAT: Credential Dumping Detection + +```kql +TrendMicro_XDR_OAT_CL +| where detail_filterRiskLevel_s == "high" +| where detail_eventName_s contains "Credential" +| project TimeGenerated, + Endpoint = detail_endpointHostName_s, + Process = detail_processName_s, + CommandLine = detail_processCmd_s, + SHA256 = detail_processFileHashSha256_s +``` + +### OAT: Process Tree Analysis + +```kql +TrendMicro_XDR_OAT_CL +| where isnotempty(detail_processName_s) +| project TimeGenerated, + Endpoint = detail_endpointHostName_s, + Process = detail_processName_s, + Parent = detail_parentName_s, + CommandLine = detail_processCmd_s +``` + +## 🌍 Supported Regions + +| Region | Value | API Endpoint | +|--------|-------|--------------| +| United States | `US` | api.xdr.trendmicro.com | +| United Kingdom / EU | `UK` | api.uk.xdr.trendmicro.com | +| Singapore / APAC | `SG` | api.sg.xdr.trendmicro.com | +| Canada | `CA` | api.ca.xdr.trendmicro.com | +| Japan | `JP` | api.jp.xdr.trendmicro.com | + +## 📁 Repository Structure + +``` +templates/ +├── workbench/ # Workbench Alerts connector (modular) +│ ├── mainTemplate.json +│ ├── createUiDefinition.json +│ └── components/ # 6 modular components +│ +├── oat/ # OAT connector (modular) +│ ├── mainTemplate.json +│ ├── createUiDefinition.json +│ └── components/ # modular components (incl. parser-function.json) +│ +├── legacy/ # Archived old templates +└── ARCHITECTURE.md # Detailed architecture documentation +``` + +## 🛠️ Advanced Deployment + +### Using Azure CLI + +**Workbench:** +```bash +az deployment group create \ + --resource-group \ + --template-uri https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/workbench/mainTemplate.json \ + --parameters workspace= trendaiRegion=US +``` + +**OAT:** +```bash +az deployment group create \ + --resource-group \ + --template-uri https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/oat/mainTemplate.json \ + --parameters workspace= trendaiRegion=US +``` + +### Testing Individual Components + +Each component can be deployed independently for testing: + +```bash +# Deploy just the custom table +az deployment group create \ + --template-file templates/workbench/components/table.json \ + --parameters workspace=test-ws workspace-location=eastus +``` + +## 🔧 Troubleshooting + +### No data after 10 minutes + +1. **Check API token**: Verify token has 'SIEM' role permissions +2. **Check region**: Ensure correct Trend Vision One region selected +3. **Check connector status**: Sentinel → Data connectors → View connector health +4. **Check DCR ingestion**: Azure Monitor → Data Collection Rules → View metrics + +### Connection fails + +- Ensure API token includes `Bearer ` prefix +- Regenerate API token if expired +- Verify workspace has Sentinel enabled + +### Missing IOC fields (Workbench) + +- Use the parser function: `TrendMicroWorkbench_Complete()` +- Parser extracts IOCs from dynamic columns automatically + +## 📚 Documentation + +New here? Start with the **[docs/](docs/)** folder — detailed, plain-language guides written for every experience level: + +- [Docs home](docs/README.md) — the map of all guides +- [Concepts — how it all fits together](docs/01-concepts.md) — what this is and *why* it's built this way +- [Permissions you need (and why)](docs/02-permissions.md) — every Azure & Trend Vision One permission, explained +- [Deploying the connector](docs/03-deployment.md) — step-by-step, portal and CLI +- [Using the connector day to day](docs/04-using-the-connector.md) — verify data, query, alerts, dashboards, filters +- [Migrating from the old connector](docs/05-migration.md) — move off the old Azure Function connector safely +- [Troubleshooting](docs/06-troubleshooting.md) — fix the common problems + +Deeper / maintainer references: + +- [Architecture Details](templates/ARCHITECTURE.md) — deep dive into component design +- [Internal test-deploy notes](docs/internal/test-deploy.md) — 🔒 maintainers only, removed before going public + +## 🤝 Support + +- **Trend Vision One API**: [Trend Micro Support](https://www.trendmicro.com/support) +- **Azure Sentinel**: [Microsoft Sentinel Documentation](https://learn.microsoft.com/azure/sentinel) +- **Issues**: [GitHub Issues](https://github.com/trendmicro/trendai-sentinel-ccf-data-connector/issues) +- **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md) + +## 🤝 Contributing + +Pull requests are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) and our [Code of Conduct](CODE_OF_CONDUCT.md). + +## 🔒 Security + +Found a vulnerability? Please **do not** open a public issue — see [SECURITY.md](SECURITY.md) for the private reporting process. + +## 📝 License + +This project is licensed under the [MIT License](LICENSE) — see the LICENSE file for details. + +## 🏆 Credits + +Built following Microsoft's [Codeless Connector Platform (CCP)](https://learn.microsoft.com/azure/sentinel/create-codeless-connector) best practices and [SentinelOne reference implementation](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/SentinelOne/Data%20Connectors/SentinelOne_ccp). + +--- + +**Version**: 2.0.0 +**Last Updated**: May 2026 +**Maintained by**: Trend Micro diff --git a/Solutions/TrendAI Vision One/SECURITY.md b/Solutions/TrendAI Vision One/SECURITY.md new file mode 100644 index 00000000000..83c9a05a8d9 --- /dev/null +++ b/Solutions/TrendAI Vision One/SECURITY.md @@ -0,0 +1,58 @@ +# Security Policy + +## Reporting a Vulnerability + +If you believe you have discovered a security vulnerability in this connector, +**please do not open a public GitHub issue.** Reporting publicly puts every +downstream user at risk before a fix is available. + +Instead, please report it privately so the maintainers can investigate and +release a fix before the issue is disclosed. + +### How to report + +- **Email:** `security@trendmicro.com` +- **Trust Center:** https://www.trendmicro.com/en_us/about/trust-center/responsible-disclosure.html +- **Zero Day Initiative:** https://www.zerodayinitiative.com/ + +When reporting, please include: + +- A description of the vulnerability and its potential impact. +- Steps to reproduce, including ARM template parameters, deploy region, and + workspace configuration where relevant. +- Affected version / commit SHA. +- Your name and contact information for follow-up (optional but helpful). + +We aim to acknowledge new reports within **3 business days** and provide a +status update within **10 business days**. + +## Scope + +This policy covers the contents of this repository: + +- ARM templates under `templates/oat/` and `templates/workbench/` +- Linked-template components (`*/components/*.json`) +- Documentation (`*.md`) +- Examples and supporting scripts + +It does **not** cover vulnerabilities in: + +- Trend Vision One product itself (use the Trend Vision One support channel). +- Microsoft Sentinel / Azure platform (use Microsoft Security Response Center + https://msrc.microsoft.com/). +- Third-party integrations that may consume data from this connector. + +## Disclosure Process + +1. Maintainer triages the report and confirms reproducibility. +2. A fix is prepared on a private branch (security advisory if appropriate). +3. The fix is reviewed and merged to `main`. +4. A new release is tagged with release notes describing the issue and + credit to the reporter (unless anonymity is requested). +5. The corresponding security advisory is published on GitHub. + +## Recognition + +We appreciate responsible disclosure. Reporters who follow this policy and +allow time to remediate before public disclosure will be credited in release +notes and the security advisory (unless they prefer to remain anonymous). diff --git a/Solutions/TrendAI Vision One/assets/trendai-logo.svg b/Solutions/TrendAI Vision One/assets/trendai-logo.svg new file mode 100644 index 00000000000..fffc3768eff --- /dev/null +++ b/Solutions/TrendAI Vision One/assets/trendai-logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Solutions/TrendAI Vision One/docs/01-concepts.md b/Solutions/TrendAI Vision One/docs/01-concepts.md new file mode 100644 index 00000000000..ede3db956c4 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/01-concepts.md @@ -0,0 +1,170 @@ +# Concepts — how it all fits together + +This page explains *what* the connector is and *why* it's built the way it is. No Azure background needed. If you only ever read one page, read this one — every other guide assumes you understand the ideas here. + +--- + +## The one-sentence version + +> This connector copies security findings from **Trend Vision One** into **Microsoft Sentinel** automatically, so your security team can investigate everything in one place. + +That's it. Everything below is just *how* that copy happens and *why* we do it the way we do. + +--- + +## The cast of characters + +Let's meet the players, each explained as if you've never seen them before. + +### Trend Vision One + +Trend Vision One is Trend Micro's security platform. It watches your endpoints, email, network, and cloud, and produces **findings** — "this laptop ran a suspicious command," "this mailbox got a phishing email," and so on. + +Think of it as a very attentive security guard who writes down everything suspicious in a notebook. + +### Microsoft Sentinel + +Microsoft Sentinel is a **SIEM** — a "Security Information and Event Management" system. In plain terms: it's a giant searchable logbook where a security team collects events from *all* their tools (not just Trend) so they can investigate, correlate, and respond in one place. + +Think of Sentinel as the central police station where every security guard in the city sends their notebook pages. + +### The problem + +The guard (Trend Vision One) keeps its notes in *its own* notebook. The police station (Sentinel) can't see them unless someone carries the pages over. **The connector is the courier** that walks the pages from Trend's notebook to Sentinel's logbook — automatically, every few minutes, forever. + +--- + +## How the courier actually works + +Sentinel runs in **Microsoft Azure** (Microsoft's cloud). To get Trend's data into a Sentinel workspace, a few small pieces of Azure plumbing have to exist. Here they are, in the order the data flows through them: + +``` + Trend Vision One API ──▶ Poller ──▶ DCE ──▶ DCR ──▶ Custom table ──▶ You (queries, alerts, dashboards) + (the security guard) (the courier) (mailbox) (sorter) (the logbook page) +``` + +| Piece | Plain-English name | What it does | Real Azure term | +|-------|--------------------|--------------|-----------------| +| **Poller** | The courier | Every few minutes it calls Trend's API, asks "anything new?", and grabs the latest findings. | The connector's built-in poller (Codeless Connector Platform) | +| **DCE** | The mailbox | A fixed address in Azure that the data gets dropped into. | Data Collection **Endpoint** | +| **DCR** | The sorter | Takes Trend's raw data and reshapes it into tidy columns before filing it. Can also drop data you don't want. | Data Collection **Rule** | +| **Custom table** | The logbook page | Where the data actually lands and lives. You query *this*. | A Log Analytics custom table (ends in `_CL`) | +| **Connector definition** | The reception desk | The page in the Sentinel portal where you type your API token and click **Connect**. | `dataConnectorDefinition` | + +The two tables data lands in are: + +- `TrendMicro_XDR_WORKBENCH_CL` — for the Workbench connector +- `TrendMicro_XDR_OAT_CL` — for the OAT connector + +> 💡 **The `_CL` suffix** just means "Custom Log." Any table you create yourself in Sentinel ends in `_CL`. Built-in Microsoft tables don't. + +--- + +## Why "codeless"? (And why you should care) + +This connector is built on Microsoft's **Codeless Connector Platform (CCP)** — sometimes written **CCF** (Codeless Connector *Framework*). Same thing. + +"Codeless" means **there is no server, no app, and no code running that you have to babysit.** The poller is a feature *inside Sentinel itself*. Microsoft runs it, patches it, and scales it for you. + +This is the single biggest reason this connector exists, so it's worth understanding what it replaced: + +| | **Old way** (Azure Function connector) | **New way** (this codeless connector) | +|---|----------------------------------------|---------------------------------------| +| What ran the courier | An **Azure Function App** — a little Python program you had to deploy and host | A poller built into Sentinel | +| Extra Azure resources | Function App, App Service Plan, Storage Account, App Insights | None | +| Who patches it | **You** (Python runtime upgrades, dependency updates) | Microsoft | +| Cost | You pay for the compute that runs the function | No compute cost (you pay only for data stored, as always) | +| Secrets it needed | Trend API token **+** your Log Analytics workspace key | Just the Trend API token | +| When it breaks | You debug a function app | You re-enter a token | + +In short: **fewer moving parts, fewer things to break, fewer bills, and less to secure.** That's the "why" behind the whole design. + +> If you're coming from the old Function App connector, the [Migration guide](05-migration.md) walks you through the switch. + +--- + +## Why so many little template files? (Modular design) + +When you click "Deploy to Azure," it doesn't deploy one giant file. It deploys a small **orchestrator** (`mainTemplate.json`) that calls several small **component** files — one for the table, one for the DCE, one for the DCR, and so on. + +Why split it up? + +- **You can fix one piece without touching the others.** Need to add a column? Edit only the table file. Need to change how data is reshaped? Edit only the DCR file. +- **You can test one piece on its own.** +- **It follows Microsoft's official recommended pattern**, which means it behaves predictably and is easier for others to review. + +You don't need to care about this to *use* the connector — it matters only if you're modifying it. The deep-dive lives in [templates/ARCHITECTURE.md](../templates/ARCHITECTURE.md). + +--- + +## Workbench vs. OAT — which one do I want? + +This trips everyone up, so here's the honest comparison. + +### Workbench Alerts — *"the conclusions"* + +Trend Vision One does its own correlation and produces **Workbench alerts**: higher-level, already-investigated incidents. One Workbench alert might bundle together several suspicious events into a single story ("possible ransomware on FINANCE-PC"). + +- **Volume:** Medium. You get fewer, richer items. +- **Best for:** Teams that want Trend's curated incidents to show up as Sentinel incidents and drive their alert queue. +- **Comes with:** A **parser function** that digs IOCs (file hashes, IPs, domains) out of the nested data for you, plus a ready-made **analytic rule** (turned off by default) and a **dashboard**. + +### OAT (Observed Attack Techniques) — *"the raw observations"* + +OAT is the firehose: **every individual detection** Trend mapped to a MITRE ATT&CK technique, including full process trees and command lines. No correlation — just the raw signal. + +- **Volume:** High. Expect a lot more rows (and therefore more storage cost). +- **Best for:** Threat hunters and detection engineers who want to write their own correlation/hunting queries over granular data. +- **Comes with:** A **universal parser function** (`TrendMicroOAT_Complete()`) that returns one stable, fully-typed schema and works across both old and new OAT data (see below). + +### How to choose + +| If you want… | Install… | +|--------------|----------| +| Trend's incidents in my Sentinel queue, minimal noise | **Workbench** | +| Raw technique-level data to hunt and build custom detections | **OAT** | +| Both — incidents *and* raw hunting data | **Both** (they don't conflict) | + +You are not locked in. Installing one doesn't affect the other, and you can add the second later. + +--- + +## What you'll have after deployment + +After you deploy, this is what exists in your Azure subscription. (Exact set depends on the connector — Workbench installs more extras than OAT.) + +| Thing | Workbench | OAT | What it's for | +|-------|:---------:|:---:|---------------| +| Custom table (`*_CL`) | ✅ | ✅ | Where data lands | +| Data Collection Endpoint (DCE) | ✅ | ✅ | The mailbox | +| Data Collection Rule (DCR) | ✅ | ✅ | The sorter/transform | +| Connector definition | ✅ | ✅ | The "Connect" page in the portal | +| Parser function | ✅ | ✅ | Workbench: extracts IOCs from nested fields. OAT: universal old+new normalizer | +| Analytic rule (disabled) | ✅ | — | Auto-creates Sentinel incidents when you enable it | +| Workbook (dashboard) | ✅ | — | Charts and overview | +| Active poller | optional* | optional* | Starts pulling data immediately | + +\* The poller is created automatically **only if you supply your API token at deploy time**. If you leave the token blank, everything else still deploys and you connect later from the portal. See [Deployment](03-deployment.md). + +> ℹ️ **Heads-up on OAT extras:** the OAT template installs the connector, table, DCR, and a parser function, but does **not** currently ship its own analytic rule or workbook the way Workbench does. The [usage guide](04-using-the-connector.md) shows OAT queries you can build into a rule or workbook yourself. + +--- + +## Key terms cheat-sheet + +Keep this handy while reading the other guides. + +| Term | Plain meaning | +|------|---------------| +| **SIEM** | The central security logbook (here: Sentinel). | +| **Workspace** | A single Sentinel/Log Analytics "logbook." Data lives in a workspace. | +| **Log Analytics** | The database engine under Sentinel that stores and searches the logs. | +| **KQL** | Kusto Query Language — the search language you type to query the data. Like SQL, but for logs. | +| **DCE** | Data Collection Endpoint — the fixed address data is delivered to. | +| **DCR** | Data Collection Rule — reshapes/filters incoming data before storing. | +| **CCP / CCF** | Codeless Connector Platform/Framework — the "no server to babysit" way of building connectors. | +| **ARM template** | A JSON file that tells Azure what to build. The "Deploy to Azure" button runs one. | +| **IOC** | Indicator of Compromise — a file hash, IP, domain, etc. that points to malicious activity. | +| **API token** | The secret password the connector uses to read data out of Trend Vision One. | + +Next up: [the permissions you'll need →](02-permissions.md) diff --git a/Solutions/TrendAI Vision One/docs/02-permissions.md b/Solutions/TrendAI Vision One/docs/02-permissions.md new file mode 100644 index 00000000000..224e2f57069 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/02-permissions.md @@ -0,0 +1,152 @@ +# Permissions you need (and why) + +This page lists **every permission** required to deploy and run the connector — on both the Azure side and the Trend Vision One side — and explains *why* each one is needed. + +Why spell out the "why"? Because in most organizations you don't grant your own access — you ask an admin. Walking in with *"I need Contributor on the resource group because the deploy creates a DCR and a custom table, and the connector needs to write to the workspace"* gets you unblocked far faster than *"the docs said I need Contributor."* + +> 🧭 **Golden rule:** ask for the **least** access that gets the job done, on the **smallest** scope (a single resource group, not the whole subscription). Every section below tells you the smallest scope that works. + +--- + +## TL;DR — the shortest path + +If you just want the request to send to your admin, here it is: + +**On the Azure side** + +| You need | On what scope | So you can… | +|----------|---------------|-------------| +| **Contributor** (or the granular set below) | The **resource group** you'll deploy into | Create the table, DCE, DCR, connector, etc. | +| **Microsoft Sentinel Contributor** | The Sentinel **workspace** | Create the connector and (optionally) the analytic rule | + +**On the Trend Vision One side** + +| You need | Where | So you can… | +|----------|-------|-------------| +| An **API key** with the **SIEM** role (Workbench role also works for Workbench) | Trend Vision One Console → API Keys | Let the connector read your findings | + +That's the whole story. The rest of this page explains each item and offers a more granular ("least-privilege") alternative for security-conscious environments. + +--- + +## Part 1 — Azure permissions (to *deploy* the connector) + +Deploying creates Azure resources, so the person clicking "Deploy to Azure" needs permission to create those resources **in the target resource group**. + +### Option A — the simple one (most teams use this) + +**Role:** `Contributor` +**Scope:** the resource group you deploy into (ideally a dedicated one, e.g. `rg-sentinel-trend`). + +Contributor lets you create and manage any resource in that resource group, but **not** hand out access to others (that's `Owner`). For a deployment, Contributor is enough and is the recommended default. + +> Why not subscription-level Owner? Because you don't need it. Scoping to one resource group means a mistake (or a compromised account) can't touch the rest of your cloud. + +### Option B — least privilege (for locked-down environments) + +If your security team won't grant blanket Contributor, here are the *specific* resource providers the deployment touches and why. Grant Contributor-equivalent rights on **just these**, scoped to the resource group: + +| Azure resource provider | What gets created | Why it's needed | +|-------------------------|-------------------|-----------------| +| `Microsoft.OperationalInsights/workspaces` | Custom table, saved function (parser) | The data has to land *somewhere*, and the parser is a saved query in the workspace | +| `Microsoft.Insights/dataCollectionEndpoints` | The DCE ("mailbox") | The fixed address data is delivered to | +| `Microsoft.Insights/dataCollectionRules` | The DCR ("sorter") | Reshapes/filters data before storage | +| `Microsoft.SecurityInsights` | Connector definition, analytic rule | Registers the connector in Sentinel and (optionally) the alert rule | +| `Microsoft.OperationsManagement/solutions` | The Sentinel solution | Ensures Sentinel is enabled on the workspace | +| `Microsoft.Insights/workbooks` | The dashboard (Workbench only) | The monitoring workbook | + +The two built-in roles that together cover almost all of the above: + +- **Microsoft Sentinel Contributor** — for the connector definition, analytic rule, and Sentinel itself. +- **Monitoring Contributor** — for the DCE and DCR. + +> ℹ️ The Azure Portal's deployment screen also shows a permissions note saying **"Read and Write permissions are required"** on the workspace. That's this same requirement, surfaced at click-time. + +### Do I need an existing Sentinel workspace? + +You need a **Log Analytics workspace**. The deployment will enable Microsoft Sentinel on it if it isn't already (that's the `sentinel-solution` step). If you don't have a workspace at all, create one first (or ask your admin to) — that's a one-time, separate task. + +--- + +## Part 2 — Azure permissions (for the connector to *run*) + +Once deployed, the connector needs to **write** the data it pulls into the custom table. With the codeless platform this is handled by the DCR and the connector's managed plumbing — **you do not provide any Azure key or secret for this.** + +This is a real improvement over the old Function App connector, which needed your **Log Analytics workspace key** (a powerful shared secret) stored in the function's settings. The codeless connector removes that secret entirely. See the [Migration guide](05-migration.md#whats-different-about-secrets) for why that matters. + +The connector definition itself declares the workspace permissions it uses: + +> **Read and Write permissions are required** on the `Microsoft.OperationalInsights/workspaces` (Workspace) scope — read, write, and delete. + +You don't grant these by hand; they're part of installing the connector into the workspace. + +--- + +## Part 3 — Trend Vision One permissions (the API token) + +The connector logs into Trend Vision One the way an app would — with an **API key** (also called an API token). This is the only secret *you* supply. + +### What role does the token need? + +| Connector | Required role on the API key | +|-----------|------------------------------| +| Workbench | **SIEM** *or* **Workbench** | +| OAT | **SIEM** | + +When in doubt, use **SIEM** — it covers both connectors and is the intended role for feeding a SIEM like Sentinel. + +### Why does it need this role and not more? + +The **SIEM** role is **read-only access to the findings feed**. It can pull alerts and detections; it **cannot** change anything in Trend Vision One. That's exactly what you want for a one-way data copy — if the token ever leaked, the worst an attacker could do is *read* your alerts, not disable your protection. + +> 🔐 **Least privilege again:** don't reuse a full-admin API key here. Make a dedicated key with only the SIEM role, used only by this connector. If it's ever compromised, you revoke that one key and nothing else breaks. + +### How to create the token (step by step) + +1. Log in to the **Trend Vision One Console**. +2. Go to **Administration → API Keys**. *(On some tenants this is under "API access management.")* +3. Click **Add API Key** / **Generate New API Key**. +4. Give it a clear name, e.g. `microsoft-sentinel-connector`, so future-you knows what it's for. +5. Assign the role: **SIEM** (or **Workbench** for the Workbench connector). +6. Save, then **copy the token immediately** — you usually can't see it again later. +7. Store it somewhere safe (a password manager / Azure Key Vault) until you paste it into the connector. + +> 📍 **Region matters.** Your token only works against *your* Trend Vision One region's API endpoint (US, UK, SG, CA, or JP). You'll pick the matching region during deployment. See [Using the connector → Regions](04-using-the-connector.md#regions-and-api-endpoints). + +### The `Bearer ` prefix gotcha + +This is the #1 cause of "connection failed." Two places ask for the token and they want it **differently**: + +| Where you enter it | Include `Bearer ` prefix? | Example | +|--------------------|:------------------------:|---------| +| **Deploy-time field** in the Azure Portal form ("Trend Vision One API Token") | ❌ **No** — paste the raw token only | `eyJhbGciOi...` | +| **Connector page** in Sentinel ("API Token") after deployment | ✅ **Yes** — include it | `Bearer eyJhbGciOi...` | + +If a connection fails, this mismatch is the first thing to check. + +--- + +## Who grants what — a quick map + +| You need… | Ask… | +|-----------|------| +| Contributor on the resource group | Your **Azure subscription admin** or whoever owns the resource group | +| Microsoft Sentinel Contributor | Your **SOC / security platform team** (they usually own Sentinel) | +| A Trend Vision One SIEM API key | Your **Trend Vision One administrator** | + +If those are three different people, send all three requests at once — they don't depend on each other. + +--- + +## Permissions checklist + +Before you start the [deployment](03-deployment.md), confirm: + +- [ ] I can deploy into a resource group (Contributor, or the granular providers above) +- [ ] Microsoft Sentinel is (or will be) enabled on the target workspace +- [ ] I have **Microsoft Sentinel Contributor** on that workspace +- [ ] I created a dedicated Trend Vision One API key with the **SIEM** role +- [ ] I saved the token somewhere safe +- [ ] I know which **region** my Trend Vision One tenant is in + +All checked? → [On to deployment.](03-deployment.md) diff --git a/Solutions/TrendAI Vision One/docs/03-deployment.md b/Solutions/TrendAI Vision One/docs/03-deployment.md new file mode 100644 index 00000000000..9a3b8c5f084 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/03-deployment.md @@ -0,0 +1,178 @@ +# Deploying the connector + +This guide installs a connector from zero. It's written so you can follow it without ever having deployed anything in Azure before. Veterans: the [Azure CLI section](#deploying-with-the-azure-cli) is probably what you want. + +> ✅ **Before you start**, make sure you've got everything on the [permissions checklist](02-permissions.md#permissions-checklist). The two things people forget: a **Trend Vision One API token** and knowing your **region**. + +--- + +## Decide two things first + +### 1. Which connector(s)? + +Workbench, OAT, or both? If you're unsure, [this section](01-concepts.md#workbench-vs-oat-which-one-do-i-want) helps you choose. You can always add the other one later. + +### 2. Connect now, or connect later? + +The deployment form has an **optional API token field**. This is a genuine fork in the road: + +| Choice | What happens | Pick this if… | +|--------|--------------|---------------| +| **Enter the token at deploy time** | Everything deploys **and** the poller starts pulling data immediately. One-and-done. | You have the token ready and want data flowing right away. | +| **Leave the token blank** | Everything deploys *except* the live poller. You connect afterward from the Sentinel portal. | The person deploying isn't the person who holds the token, or you want to separate "infra" from "secrets." | + +Both are fully supported. This guide covers both. + +--- + +## Option 1 — Deploy with the "Deploy to Azure" button (recommended) + +This is the point-and-click path. + +### Step 1 — Click the button + +In the main [README](../README.md#-quick-deploy), click **Deploy to Azure** next to the connector you want. Your browser opens the Azure Portal with the deployment form pre-loaded. + +> If you see a sign-in prompt, log in with the Azure account that has the [permissions](02-permissions.md) from the checklist. + +### Step 2 — Fill in the form + +You'll see a custom form. Here's every field and what to put: + +| Field | What to enter | Notes | +|-------|---------------|-------| +| **Subscription** | The Azure subscription that holds your Sentinel workspace | If you only have one, it's pre-selected | +| **Resource group** | Pick an existing one, or create a new one like `rg-sentinel-trend` | A dedicated group keeps things tidy and easy to clean up | +| **Region / Location** | The **Azure** region of your workspace | This is the *Azure* region, not the Trend region — keep them the same as your workspace | +| **Workspace** | Choose your Sentinel workspace from the dropdown | The dropdown lists workspaces in the selected resource group | +| **Trend Vision One Region** | The region your **Trend** tenant lives in: US, UK, SG, CA, or JP | Must match your tenant — wrong region = no data. See [regions](04-using-the-connector.md#regions-and-api-endpoints) | +| **Trend Vision One API Token** | *(optional)* Paste the **raw** token — **no** `Bearer ` prefix | Leave blank to connect later. See the [prefix gotcha](02-permissions.md#the-bearer--prefix-gotcha) | +| **Optional TMV1-Filter** *(Workbench)* | *(optional)* A filter expression, e.g. `(severity ge 'high')` | Limits which alerts are pulled. Leave blank for everything. See [filters](04-using-the-connector.md#filtering-what-gets-ingested) | +| **OAT Filter** *(OAT)* | *(optional)* e.g. `(riskLevel eq 'high')` | Same idea, for OAT | +| **Exclude third-party OAT** *(OAT)* | Defaults to **on (true)** | Drops detections that came from non-Trend linked sources. Leave on unless you specifically want them | + +### Step 3 — Review and create + +1. Click **Review + create**. +2. Azure validates the form. If it complains, fix the highlighted field and try again. +3. Click **Create**. +4. Wait. Deployment takes about **3–5 minutes**. You'll see a "Deployment in progress" screen, then "Your deployment is complete." + +### Step 4 — If you left the token blank, connect now + +*(Skip this if you entered the token at deploy time — you're already connected.)* + +1. Go to **Microsoft Sentinel → Data connectors**. +2. Search for **"Trend Vision One - Workbench Alerts"** or **"Trend Vision One - OAT"**. +3. Click it, then **Open connector page**. +4. In the **API Token** box, paste your token **with** the `Bearer ` prefix: + `Bearer eyJhbGciOi...` +5. Click **Connect**. + +> 🔁 **Two different token formats!** Deploy-time field = **no** prefix. Connector page = **with** `Bearer ` prefix. This catches everyone once. + +### Step 5 — Confirm it worked + +Jump to [Using the connector → Verify data is flowing](04-using-the-connector.md#step-1-confirm-data-is-arriving). Data appears within **5–10 minutes** of connecting. + +--- + +## Option 2 — Deploying with the Azure CLI + +For automation, repeatable deployments, or if you just prefer a terminal. + +### Prerequisites + +```bash +# Install the Azure CLI if you don't have it +# macOS: brew install azure-cli +# Other: https://learn.microsoft.com/cli/azure/install-azure-cli + +az login +az account set --subscription "" +``` + +### Deploy Workbench + +```bash +az deployment group create \ + --resource-group \ + --template-uri https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/workbench/mainTemplate.json \ + --parameters \ + workspace= \ + trendaiRegion=US +``` + +### Deploy OAT + +```bash +az deployment group create \ + --resource-group \ + --template-uri https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/oat/mainTemplate.json \ + --parameters \ + workspace= \ + trendaiRegion=US +``` + +### Connecting at deploy time via CLI (optional) + +Add the API token to start the poller immediately. **Use the raw token, no `Bearer ` prefix.** Never hard-code a secret — read it from an environment variable or Key Vault: + +```bash +az deployment group create \ + --resource-group \ + --template-uri https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/workbench/mainTemplate.json \ + --parameters \ + workspace= \ + trendaiRegion=US \ + apikey="$TREND_API_TOKEN" \ + workbenchFilter="(severity ge 'high')" +``` + +### All available parameters + +| Parameter | Applies to | Default | Meaning | +|-----------|------------|---------|---------| +| `workspace` | both | *(required)* | Log Analytics / Sentinel workspace name | +| `workspace-location` | both | resource group's location | Azure region of the workspace | +| `trendaiRegion` | both | `US` | Trend region: `US`, `UK`, `SG`, `CA`, `JP` | +| `apikey` | both | *(empty)* | Raw Trend API token. Empty = deploy without the poller | +| `workbenchFilter` | Workbench | *(empty)* | TMV1-Filter expression for Workbench alerts | +| `oatFilter` | OAT | *(empty)* | TMV1-Filter expression for OAT detections | +| `excludeThirdPartyOat` | OAT | `true` | Drop detections from third-party linked sources | + +--- + +## What got created (so you can find it later) + +After a successful Workbench deploy, your resource group contains: + +- A custom table: `TrendMicro_XDR_WORKBENCH_CL` +- A Data Collection Endpoint and a Data Collection Rule +- The connector definition (visible under Sentinel → Data connectors) +- A parser function: `TrendMicroWorkbench_Complete()` +- An analytic rule (named *"Trend Vision One - Create Incident for Workbench Alerts"*), **disabled** by default +- A workbook: *"TrendVisionOneWorkbenchOverview"* + +OAT deploys the table (`TrendMicro_XDR_OAT_CL`), DCE, DCR, connector definition, and a parser function: `TrendMicroOAT_Complete()`. (OAT does not ship its own analytic rule or workbook — see [usage](04-using-the-connector.md).) + +The Azure Portal also prints a **"Deployment complete"** message in the outputs with these same next steps. + +--- + +## Deploying both connectors + +Just run the process twice — once per connector. They share nothing that conflicts, and you can deploy them into the same resource group and workspace. + +--- + +## Government cloud (Azure US Gov) + +The README includes separate **Deploy to Azure US Gov** buttons that target `portal.azure.us`. Use those instead of the commercial buttons if your Sentinel runs in Azure Government. Everything else in this guide is identical. + +--- + +## Next steps + +- ✅ [Verify data is flowing and learn to query it](04-using-the-connector.md) +- ❌ No data after 10 minutes? → [Troubleshooting](06-troubleshooting.md) diff --git a/Solutions/TrendAI Vision One/docs/04-using-the-connector.md b/Solutions/TrendAI Vision One/docs/04-using-the-connector.md new file mode 100644 index 00000000000..aec71ba37dd --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/04-using-the-connector.md @@ -0,0 +1,218 @@ +# Using the connector day to day + +You've deployed and connected. Now what? This guide covers everything you'll actually *do* with the connector: confirming data arrives, querying it, turning on alerts, reading dashboards, filtering noise, and the region/secret housekeeping. + +It assumes no KQL experience. If you've written SQL, you'll feel at home; if you haven't, you'll still be fine — every query here is copy-paste ready. + +--- + +## A 60-second KQL primer + +KQL (Kusto Query Language) is how you ask Sentinel questions. You read it **top to bottom**, and each `|` ("pipe") passes results to the next step, like an assembly line. + +```kql +TrendMicro_XDR_WORKBENCH_CL // 1. Start with this table +| where TimeGenerated > ago(1h) // 2. Keep only the last hour +| project TimeGenerated, severity_s, workbenchName_s // 3. Show only these columns +| take 10 // 4. Just the first 10 rows +``` + +Where do you type this? **Sentinel → Logs** (or **Log Analytics → Logs**). Paste, hit **Run**. + +> 💡 **Why do columns end in `_s`, `_d`, `_t`, `_g`?** Log Analytics tags each column with its type: `_s` = string (text), `_d` = double (number), `_t` = datetime, `_g` = GUID, `_b` = boolean. So `severity_s` is the text severity, `priorityScore_d` is a number. + +--- + +## Step 1 — Confirm data is arriving + +Right after connecting, run the matching query. Give it **5–10 minutes** after you click Connect. + +**Workbench:** +```kql +TrendMicro_XDR_WORKBENCH_CL +| where TimeGenerated > ago(1h) +| project TimeGenerated, workbenchId_s, severity_s, workbenchName_s +| take 10 +``` + +**OAT:** +```kql +TrendMicro_XDR_OAT_CL +| where TimeGenerated > ago(1h) +| project TimeGenerated, entityType_s, detail_endpointHostName_s, detail_filterRiskLevel_s +| take 10 +``` + +- **Rows come back?** 🎉 You're done — the connector works. Skip ahead to querying. +- **Empty, even after 10 minutes?** → [Troubleshooting](06-troubleshooting.md). The usual culprits are the wrong region or the missing `Bearer ` prefix. + +You can also watch connector health visually: **Sentinel → Data connectors →** your connector **→** the *"Data received"* graph and *"Last data received"* timestamp. + +--- + +## Step 2 — Query the data + +### Workbench: high-severity alerts + +```kql +TrendMicro_XDR_WORKBENCH_CL +| where severity_s in ("high", "critical") +| project TimeGenerated, workbenchId_s, workbenchName_s, severity_s, priorityScore_d +| sort by TimeGenerated desc +``` + +### OAT: high-risk detections + +```kql +TrendMicro_XDR_OAT_CL +| where detail_filterRiskLevel_s == "high" +| project TimeGenerated, detail_endpointHostName_s, detail_processCmd_s, detail_processFileHashSha256_s +| sort by TimeGenerated desc +``` + +### OAT: process-tree style view + +```kql +TrendMicro_XDR_OAT_CL +| where isnotempty(detail_processName_s) +| project TimeGenerated, + Endpoint = detail_endpointHostName_s, + Process = detail_processName_s, + Parent = detail_parentName_s, + CommandLine= detail_processCmd_s +``` + +The [main README](../README.md#-data-schemas) lists the column categories for both tables (Workbench has 56 columns; OAT has 139). + +--- + +## Step 3 — The parser functions + +Both connectors install a **parser function** — a saved query you call like a table. Both are **universal**: they auto-detect the data shape and work on rows from **both** the old Function App connector and this new one, so after a migration your historical rows still parse correctly. (More in the [migration guide](05-migration.md).) + +### Workbench: `TrendMicroWorkbench_Complete()` + +Workbench alerts arrive with some data tucked inside nested fields (lists of indicators, entities, matched rules). Picking those apart by hand is tedious, so the parser returns the same data with **IOCs already extracted into flat columns** (`FileName_s`, `FileHashValue_s`, `IPAddress`, `DomainName_s`, `URL_s`, …): + +```kql +TrendMicroWorkbench_Complete() +| where severity_s in ("high", "critical") +| where isnotempty(FileHashValue_s) +| project TimeGenerated, workbenchName_s, FileName_s, FileHashValue_s, HostHostName_s +``` + +> 🧠 **Why it exists:** it saves you from writing `mv-expand` / `parse_json` gymnastics every time you want a file hash. Use the raw table for simple fields; use the parser when you want IOCs. + +### OAT: `TrendMicroOAT_Complete()` + +OAT fields are already flat (`detail_*`), so you *can* query the raw table directly. But the parser still earns its keep: it returns **one stable, fully-typed schema** no matter how the row was ingested — old Function App data, current connector data, or older variants where the payload was kept as a whole `detail` object or `RawData` string. For every field it prefers the typed flat column and falls back to re-deriving it from the raw payload, so a query you write today keeps working across all of that history. + +```kql +TrendMicroOAT_Complete() +| where detail_filterRiskLevel_s == "high" +| project TimeGenerated, detail_endpointHostName_s, detail_processCmd_s, detail_processFileHashSha256_s +``` + +It also adds two convenience columns pulled from the detection's filters: `mitreTacticIds_s` and `mitreTechniqueIds_s`. + +> 🧠 **When to use which:** for simple, recent queries the raw `TrendMicro_XDR_OAT_CL` table is fine. Reach for `TrendMicroOAT_Complete()` when you want guaranteed column/type stability across mixed old + new data (especially right after a migration). + +--- + +## Step 4 — Turn on the analytic rule (Workbench) + +An **analytic rule** is a saved query Sentinel runs on a schedule; when it finds something, it **creates an incident** in your queue. The Workbench deployment ships one, **turned off** so it can't surprise you. + +To enable it: + +1. **Sentinel → Analytics**. +2. Search **"Trend Vision One"**. +3. Open **"Trend Vision One - Create Incident for Workbench Alerts"**. +4. **Edit → Enable → Save**. + +What it does once on: + +- Runs every **5 minutes**. +- Creates an incident per Workbench alert, mapping entities Sentinel understands — **Account, File, Process, Registry Key, Registry Value**. +- Groups alerts that share the same **WorkbenchID** so one logical incident isn't split into many. +- Maps Trend severity onto Sentinel severity and carries useful custom details (Workbench link, priority score, customer ID). + +> ⚠️ **Turn it on deliberately.** Once enabled it starts generating incidents immediately. Make sure your team is ready to triage them — and if you also run the old connector's rule, see the [migration guide](05-migration.md#avoid-double-incidents) to avoid duplicate incidents. + +### OAT alerting + +OAT does not ship a prebuilt rule. To alert on OAT, create a scheduled analytic rule (**Analytics → Create → Scheduled query rule**) using an OAT query like the high-risk one above as the rule logic. + +--- + +## Step 5 — The dashboard / workbook (Workbench) + +A **workbook** is an interactive dashboard. Workbench installs *"TrendVisionOneWorkbenchOverview"*: + +1. **Sentinel → Workbooks → My workbooks**. +2. Open **"TrendVisionOneWorkbenchOverview"**. + +It shows alert trends (7- and 30-day), severity breakdown, detection-model usage, and top affected hosts. OAT does not ship a workbook; you can build one from the OAT queries above. + +--- + +## Filtering what gets ingested + +Two knobs let you ingest *less*, which lowers noise and storage cost. Both are set **at deploy time** (Portal form or CLI parameter). + +### TMV1-Filter (`workbenchFilter` / `oatFilter`) + +A filter expression sent to the Trend API so it only returns matching items. Examples: + +| Connector | Example filter | Effect | +|-----------|----------------|--------| +| Workbench | `(severity ge 'high')` | Only high and critical alerts | +| OAT | `(riskLevel eq 'high')` | Only high-risk detections | + +Leave it empty to ingest everything. To change it later, redeploy with the new value (it's a deploy-time parameter). + +### Exclude third-party OAT (`excludeThirdPartyOat`, default `true`) + +OAT can include detections forwarded from **non-Trend, third-party linked sources**. By default these are excluded to keep the feed focused on Trend's own detections. Set it to `false` only if you specifically want third-party detections too. + +> 💰 **Why filtering matters:** Sentinel bills by **data ingested and stored**. OAT especially is high-volume. Filtering at the source is the cheapest, simplest way to control cost — far better than ingesting everything and deleting later. + +--- + +## Regions and API endpoints + +Your Trend Vision One tenant lives in one region, and the connector must call that region's API. You pick this as **Trend Vision One Region** during deployment. + +| Region | Value | API endpoint | +|--------|-------|--------------| +| United States | `US` | `api.xdr.trendmicro.com` | +| United Kingdom / EU | `UK` | `api.uk.xdr.trendmicro.com` | +| Singapore / APAC | `SG` | `api.sg.xdr.trendmicro.com` | +| Canada | `CA` | `api.ca.xdr.trendmicro.com` | +| Japan | `JP` | `api.jp.xdr.trendmicro.com` | + +> ❗ **Wrong region = no data and no obvious error.** The token authenticates per-region. If you picked the wrong one, the connector can't see your findings. Not sure which region you're in? Check the URL of your Trend Vision One Console, or ask your Trend admin. + +--- + +## Rotating or replacing the API token + +Tokens expire or get rotated for hygiene. When that happens, data quietly stops. To update it: + +1. Create a fresh token in Trend Vision One (same **SIEM** role). +2. **Sentinel → Data connectors →** your connector **→ Open connector page**. +3. Paste the new token **with** the `Bearer ` prefix. +4. Click **Disconnect**, then **Connect** again with the new token. + +Set yourself a calendar reminder before the token's expiry so the feed never goes dark. + +--- + +## Daily-driver checklist + +- **Is data current?** Check *"Last data received"* on the connector page, or run the [Step 1](#step-1-confirm-data-is-arriving) query. +- **Too noisy / too expensive?** Add or tighten a [filter](#filtering-what-gets-ingested). +- **Not enough alerts becoming incidents?** Make sure the [analytic rule is enabled](#step-4-turn-on-the-analytic-rule-workbench). +- **Feed went dark?** Token probably expired → [rotate it](#rotating-or-replacing-the-api-token), or check [troubleshooting](06-troubleshooting.md). + +Next: [migrating from the old connector →](05-migration.md) diff --git a/Solutions/TrendAI Vision One/docs/05-migration.md b/Solutions/TrendAI Vision One/docs/05-migration.md new file mode 100644 index 00000000000..21c961870f8 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/05-migration.md @@ -0,0 +1,222 @@ +# Migrating from the old connector + +If you already pull Trend Vision One data into Sentinel using the **old Azure Function based connector**, this guide moves you onto the new **codeless** connector — safely, in plain steps, without losing your historical data or breaking your existing queries. + +Read the whole page once before you start. It's written to remove every "wait, what about…?" before you touch anything. + +--- + +## Are you actually on the old connector? (How to tell) + +You're on the old one if **any** of these is true in your Azure environment: + +- There's an **Azure Function App** with a name like `TrendMicroXDR…` (Sentinel → Data connectors, or just search "Function App" in the portal). +- You see the data connector titled simply **"Trend Vision One"** (connector id `TrendMicroXDR`) — *not* "Trend Vision One - Workbench Alerts" / "- OAT". +- Your resource group has a **Storage Account** + **App Service Plan** that exist only to run that function. + +If none of that exists and you've never deployed a Trend connector before, you don't need this page — go straight to [Deployment](03-deployment.md). + +--- + +## The big picture (why this is low-risk) + +Here's the single most reassuring fact: + +> **The old connector and the new connector write to the *same tables*, with the *same column names*.** + +| | Old (Azure Function) | New (Codeless) | +|---|----------------------|----------------| +| Workbench table | `TrendMicro_XDR_WORKBENCH_CL` | `TrendMicro_XDR_WORKBENCH_CL` ✅ same | +| OAT table | `TrendMicro_XDR_OAT_CL` | `TrendMicro_XDR_OAT_CL` ✅ same | +| Column names | `detail_*_s`, `endpoint_ips_s`, `severity_s`, … | **deliberately identical** ✅ | + +The new connector was **purpose-built to be drop-in compatible**: the OAT connector preserves the exact legacy column shapes (`detail_*_s` prefix, `endpoint_ips_s` / `endpoint_name_s` / `endpoint_guid_g` expansion, lowercase `xdrCustomerId_g`) and even keeps the full raw payload in a `RawData` column as a fallback. **Both** connectors ship a **universal parser** — `TrendMicroWorkbench_Complete()` and `TrendMicroOAT_Complete()` — that reads old and new rows alike and returns one stable schema, so queries that call the parser span your entire history seamlessly. + +**What this means for you:** + +- ✅ Your **historical data stays** — same table, nothing deleted. +- ✅ Your **existing KQL queries keep working** — same column names. +- ✅ Your **analytic rules and workbooks keep working** — they reference the same columns. +- ✅ New data simply continues landing in the same table, just delivered by a different (better) courier. + +So the migration is really just: **stand up the new courier, confirm it's delivering, then retire the old courier.** The data store underneath never changes. + +--- + +## What's genuinely different + +Three real differences to be aware of before you start. + +### 1. The infrastructure disappears + +The old connector ran a whole little app stack. The new one runs inside Sentinel. After migrating, you get to **delete** all of this: + +| Old resource | Why it existed | After migration | +|--------------|----------------|-----------------| +| Azure Function App | Ran the Python poller | ❌ Delete | +| App Service Plan | Hosting/compute for the function | ❌ Delete | +| Storage Account | Function state / checkpoints | ❌ Delete (if dedicated to it) | +| Application Insights | Function logging | ❌ Delete (if dedicated to it) | + +Result: less to patch, less to pay for, less to secure. + +### 2. What's different about secrets + +The old connector needed **two** secrets in the function's app settings: + +- your Trend Vision One **API token**, and +- your **Log Analytics workspace key** (a powerful shared secret that can write anything into your workspace). + +The new connector needs **only the Trend API token**. The workspace key is gone entirely — the codeless platform handles ingestion through the DCR without a shared key. That's one fewer high-value secret to store, rotate, and worry about. + +### 3. Region codes changed format + +The old function used lowercase region codes; the new connector uses the official short codes: + +| Old function region code | New connector region value | +|--------------------------|----------------------------| +| `us` | `US` | +| `eu` | `UK` *(EU is served by the UK endpoint)* | +| `sg` | `SG` | +| `jp` | `JP` | +| — | `CA` *(new)* | +| `au`, `in` | ⚠️ **not currently offered** by this connector | + +> ⚠️ **If your old connector used `au` or `in`:** the new connector currently supports US, UK, SG, CA, JP only. **Stop and contact Trend Micro support** before migrating, so you don't end up unable to point at your region. Don't decommission the old connector until you've confirmed coverage. + +### Also worth knowing: the RCA tables + +The old connector could also populate two root-cause-analysis tables: `TrendMicro_XDR_RCA_Task_CL` and `TrendMicro_XDR_RCA_Result_CL`. The new Workbench/OAT connectors **do not** produce these. If you actively use RCA data, note that: + +- Your historical RCA data stays (tables aren't deleted). +- No *new* RCA rows will arrive after you retire the old connector. +- If RCA is important to your workflow, raise it with Trend support before fully decommissioning. + +--- + +## The migration plan (overview) + +``` +1. Prep → 2. Deploy new (parallel) → 3. Verify → 4. Stop the old → 5. Decommission → 6. Cleanup + gather info new connector alongside data is disable old delete old remove old + the old one flowing poller/rule function stack analytic rule +``` + +The key idea: **run both in parallel just long enough to confirm the new one works, then cut over.** We never delete first. + +> ⏱️ **Plan for a short overlap window** (an hour is plenty). During overlap both connectors write to the same table — see [avoiding duplicates](#avoid-double-incidents) for how to handle that cleanly. + +--- + +## Step-by-step + +### Step 1 — Prep: gather your facts + +Before changing anything, write down: + +- [ ] Your **Trend region** (translate the old code using the [table above](#3-region-codes-changed-format)). +- [ ] Which connectors you need: **Workbench, OAT, or both**. +- [ ] Whether the old connector used `au`/`in` (if so, [stop and contact support](#3-region-codes-changed-format)). +- [ ] Whether you rely on the **RCA tables** (if so, flag with support). +- [ ] A **fresh Trend Vision One API token** with the **SIEM** role ([how-to](02-permissions.md#how-to-create-the-token-step-by-step)). Make a *new* one rather than reusing the function's — you'll revoke the old one at the end. +- [ ] Note your current old-connector analytic rules and which are **enabled**, so you can recreate/replace them. + +### Step 2 — Deploy the new connector alongside the old one + +Deploy the new connector following the [deployment guide](03-deployment.md). **Leave the old connector running for now.** + +Because both write to the same table, the new connector will start adding rows next to the old connector's rows — that's expected and fine for a short window. + +> 💡 You can deploy **without** the API token first (infra only), then connect when you're ready to start the overlap window. That gives you control over exactly when dual-ingestion begins. + +### Step 3 — Verify the new connector is delivering + +Confirm new data is arriving via the new path. Run (Workbench shown; adjust table for OAT): + +```kql +TrendMicro_XDR_WORKBENCH_CL +| where TimeGenerated > ago(30m) +| summarize Rows = count(), Latest = max(TimeGenerated) +``` + +You want a recent `Latest` timestamp and a non-zero count. Also check **Sentinel → Data connectors →** *"Trend Vision One - Workbench Alerts"* shows a healthy *"Last data received."* + +Spot-check that your existing queries still return what you expect — they should, since columns are unchanged: + +```kql +TrendMicroWorkbench_Complete() +| where TimeGenerated > ago(30m) +| project TimeGenerated, severity_s, FileName_s, FileHashValue_s, HostHostName_s +| take 20 +``` + +✅ Only proceed once you're satisfied the new connector is healthy. + +### Step 4 — Stop the old connector (but don't delete yet) + +Now turn **off** the old courier so only the new one is ingesting: + +1. Find the old **Function App** (e.g. `TrendMicroXDR…`). +2. **Stop** it: Function App → **Overview → Stop**. (Stopping, not deleting, lets you roll back instantly if needed.) +3. If the old connector installed its own **analytic rule(s)**, **disable** them now so you don't get duplicate incidents (see below). + +> 🔁 **Rollback if something's wrong:** if the new connector misbehaves, just **Start** the old Function App again. Because nothing was deleted, you're instantly back to the old path. This is why we stop before we delete. + +### Step 5 — Avoid double incidents + + + +During the brief overlap, both connectors wrote rows to the same table. Two things to handle: + +- **Duplicate rows for the overlap window.** Harmless for most uses; they're just two copies of the same finding for that hour. If you care, filter them in queries, or simply ignore — they age out with your retention. +- **Duplicate incidents.** If *both* the old and new analytic rules are enabled, each finding could create two incidents. Fix: keep **only one** rule enabled. Recommended: enable the **new** Workbench rule ([usage guide](04-using-the-connector.md#step-4-turn-on-the-analytic-rule-workbench)) and **disable the old** one in Step 4. + +### Step 6 — Decommission the old infrastructure + +Once the new connector has run cleanly on its own for a comfortable period (a day or two is a safe default), delete the old stack. Delete only resources that exist **solely** for the old connector: + +1. Delete the **Function App**. +2. Delete its **App Service Plan**. +3. Delete its dedicated **Storage Account** and **Application Insights** (only if nothing else uses them). +4. **Remove the old data connector** entry: Sentinel → Data connectors → "Trend Vision One" (`TrendMicroXDR`) → disconnect/remove. +5. **Delete the old analytic rule(s)** you disabled in Step 4 (if you've replaced them with the new ones). +6. **Revoke the old API token** in Trend Vision One (the one the function used). The new connector has its own token, so the old one is now dead weight — revoking it shrinks your exposure. + +> 🧹 **Do not delete the tables** (`TrendMicro_XDR_*_CL`). The new connector uses them and they hold your history. + +### Step 7 — Final verification + +- [ ] New connector shows recent *"Last data received."* +- [ ] Your dashboards/queries still populate. +- [ ] Exactly **one** analytic rule per data type is enabled. +- [ ] Old Function App and its stack are gone. +- [ ] Old API token revoked. +- [ ] No unexpected Azure charges from leftover old resources. + +🎉 You're migrated. + +--- + +## FAQ + +**Will I lose my historical data?** +No. Same tables, never deleted. Old rows stay queryable forever (subject to your normal retention settings). + +**Will my existing KQL / rules / workbooks break?** +No — column names are intentionally identical. The Workbench parser even handles old *and* new rows automatically. + +**Can I run both connectors permanently?** +You *can*, but you shouldn't — you'd pay to ingest everything twice and risk duplicate incidents. The whole point is to retire the old one. + +**What if I'm mid-migration and need to roll back?** +Before Step 6, rollback is trivial: **Start** the old Function App, disable the new poller. Nothing's been deleted. + +**My region was `au` or `in`.** +The new connector doesn't currently offer those. [Contact Trend support](#3-region-codes-changed-format) before decommissioning the old connector. + +**I rely on the RCA tables.** +The new connector doesn't produce them. Your historical RCA data stays, but no new RCA rows arrive after cutover. Flag this with Trend support before fully decommissioning. + +--- + +Stuck during migration? → [Troubleshooting](06-troubleshooting.md) diff --git a/Solutions/TrendAI Vision One/docs/06-troubleshooting.md b/Solutions/TrendAI Vision One/docs/06-troubleshooting.md new file mode 100644 index 00000000000..4b500120c00 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/06-troubleshooting.md @@ -0,0 +1,100 @@ +# Troubleshooting + +Most problems fall into a handful of buckets. Find your symptom below; each fix explains *why* it works so you learn the system, not just the workaround. + +> 🩺 **First, the 90% fixes.** Before anything else, check these two — they cause the large majority of issues: +> 1. **Wrong region.** The Trend region you picked must match your tenant. ([Regions](04-using-the-connector.md#regions-and-api-endpoints)) +> 2. **The `Bearer ` prefix.** Connector page wants `Bearer `; the deploy-time field wants the raw token with **no** prefix. ([Prefix gotcha](02-permissions.md#the-bearer--prefix-gotcha)) + +--- + +## No data after 10 minutes + +Symptom: connector deployed and connected, but the verification query returns nothing. + +Work through these in order: + +1. **Did you actually connect?** If you left the API token blank at deploy time, the poller doesn't exist yet. Go to Sentinel → Data connectors → your connector → **Open connector page** → enter the token (with `Bearer `) → **Connect**. +2. **Right region?** Wrong region authenticates but sees no findings — silent emptiness. Confirm against your Trend Vision One Console URL. +3. **Token role?** The token needs the **SIEM** role (or **Workbench** for the Workbench connector). A token with the wrong role can't read the feed. +4. **Is there anything to pull?** If you set a tight filter (e.g. `(severity ge 'high')`) and there simply are no high-severity items in the window, the table is legitimately empty. Loosen the filter to test. +5. **Give it time.** First data can take **5–10 minutes**. The poll window is a few minutes wide. +6. **Check connector health:** Sentinel → Data connectors → your connector → look at *"Data received"* and *"Last data received."* + +```kql +// Quick "is anything landing?" check +TrendMicro_XDR_WORKBENCH_CL // or TrendMicro_XDR_OAT_CL +| where TimeGenerated > ago(2h) +| summarize Rows = count(), Latest = max(TimeGenerated) +``` + +--- + +## "Connection failed" when I click Connect + +- **Missing `Bearer ` prefix** on the connector page → add it. This is the most common cause. +- **Expired or revoked token** → generate a fresh one in Trend Vision One and reconnect. +- **Wrong region** → the token can't authenticate against a region it doesn't belong to. +- **Copy/paste whitespace** → re-copy the token; a stray leading/trailing space breaks it. + +To replace the token cleanly: **Disconnect**, paste the new `Bearer `, **Connect**. ([Rotating tokens](04-using-the-connector.md#rotating-or-replacing-the-api-token)) + +--- + +## Deployment itself failed + +- **Permission denied / authorization errors** → you're missing rights on the resource group or workspace. See [Permissions](02-permissions.md). You typically need **Contributor** on the resource group **and** **Microsoft Sentinel Contributor** on the workspace. +- **Workspace dropdown is empty** → the form filters workspaces by the selected **resource group**. Pick the resource group that actually contains your Sentinel workspace. +- **"Resource provider not registered"** → register the providers listed in [permissions](02-permissions.md#option-b--least-privilege-for-locked-down-environments) on the subscription (an admin task), then redeploy. +- **A nested template URL 404s** → the component templates are fetched from GitHub raw URLs at deploy time. If the repo/branch moved, the `baseUrl` in `mainTemplate.json` is stale. (Internal/test deploys use a blob mirror — see [internal notes](internal/test-deploy.md).) + +--- + +## Data is flowing but my IOC columns are empty (Workbench) + +The raw table keeps indicators/entities inside nested fields. Use the **parser function**, which flattens them: + +```kql +TrendMicroWorkbench_Complete() +| where isnotempty(FileHashValue_s) +| project TimeGenerated, workbenchName_s, FileName_s, FileHashValue_s, IPAddress +``` + +If the parser function doesn't exist, the Workbench deployment's parser step didn't run — redeploy the Workbench template (it installs `TrendMicroWorkbench_Complete()`). + +--- + +## No incidents are being created (Workbench) + +Incidents come from the **analytic rule**, which ships **disabled**. Enable it: Sentinel → Analytics → *"Trend Vision One - Create Incident for Workbench Alerts"* → **Edit → Enable → Save**. ([Details](04-using-the-connector.md#step-4-turn-on-the-analytic-rule-workbench)) + +OAT ships no rule — you create your own scheduled rule for OAT. + +--- + +## I'm getting duplicate incidents + +Usually means **two analytic rules are enabled** for the same data — commonly the old connector's rule plus the new one during a migration. Keep exactly **one** enabled. See [migration → avoid double incidents](05-migration.md#avoid-double-incidents). + +--- + +## My bill went up + +- **OAT is high-volume** by design. If you turned it on without a filter, you're ingesting everything. Add a [filter](04-using-the-connector.md#filtering-what-gets-ingested) (`oatFilter`) and/or keep `excludeThirdPartyOat=true`. +- **Running old + new connectors in parallel** ingests data twice. Finish the [migration](05-migration.md) and retire the old one. + +--- + +## Migration-specific issues + +See the [migration FAQ](05-migration.md#faq) for: rollback, `au`/`in` regions, RCA tables, and historical-data questions. + +--- + +## Still stuck? Where to get help + +- **Trend Vision One API / token / region questions** → [Trend Micro Support](https://www.trendmicro.com/support) +- **Microsoft Sentinel / Azure / DCR questions** → [Microsoft Sentinel docs](https://learn.microsoft.com/azure/sentinel) +- **A bug in these templates or docs** → [open a GitHub issue](https://github.com/trendmicro/trendai-sentinel-ccf-data-connector/issues) + +When filing an issue, include: which connector (Workbench/OAT), your region, whether you connected at deploy-time or via the portal, the exact error text, and the output of the "is anything landing?" query above (with sensitive values redacted). diff --git a/Solutions/TrendAI Vision One/docs/README.md b/Solutions/TrendAI Vision One/docs/README.md new file mode 100644 index 00000000000..f206b4b2992 --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/README.md @@ -0,0 +1,39 @@ +# Documentation + +Welcome! This folder explains the **Trend Vision One → Microsoft Sentinel data connectors** in plain language — no prior Azure or Sentinel experience assumed. + +The goal of these docs is simple: **anyone, from a first-day analyst to a veteran cloud engineer, should be able to read a page and understand not just *what* to click, but *why*.** If a page ever assumes knowledge you don't have, that's a bug in the docs — please open an issue. + +## Start here + +Read these in order if you're new: + +| # | Guide | Read this if you want to… | +|---|-------|---------------------------| +| 1 | [Concepts — how it all fits together](01-concepts.md) | Understand *what* this is and *why* it's built the way it is, in everyday terms. | +| 2 | [Permissions you need (and why)](02-permissions.md) | Know exactly which Azure and Trend Vision One permissions are required, and *why* each one is needed, before you ask IT for access. | +| 3 | [Deploying the connector](03-deployment.md) | Install a connector, step by step, with screenshots-worth of detail. | +| 4 | [Using the connector day to day](04-using-the-connector.md) | Verify data is flowing, write queries, turn on alerts, and read the dashboards. | +| 5 | [Migrating from the old connector](05-migration.md) | Move off the old Azure Function based "Trend Vision One" connector onto this one — safely, without losing data. | +| 6 | [Troubleshooting](06-troubleshooting.md) | Fix the common "no data / connection failed" problems. | + +## Quick links by role + +- **"I just need it installed."** → [Deploying the connector](03-deployment.md) +- **"I have to request access first."** → [Permissions you need](02-permissions.md) +- **"We already use the old Trend Micro connector."** → [Migration guide](05-migration.md) +- **"Data isn't showing up."** → [Troubleshooting](06-troubleshooting.md) +- **"I'm a maintainer / Trend internal."** → [Internal test-deploy notes](internal/test-deploy.md) + +## A note on the two connectors + +There are **two** connectors in this repository. They are independent — you can install one, the other, or both. + +- **Workbench Alerts** — the curated security incidents Trend Vision One has already correlated for you ("here is a thing worth looking at"). Medium data volume. +- **OAT (Observed Attack Techniques)** — the raw, high-volume stream of individual MITRE ATT&CK-mapped detections ("here is every suspicious technique we saw"). High data volume. + +[Concepts](01-concepts.md#workbench-vs-oat-which-one-do-i-want) explains the difference in more detail and helps you choose. + +--- + +*These docs describe version 2.x of the connectors. Last reviewed: June 2026.* diff --git a/Solutions/TrendAI Vision One/docs/internal/test-deploy.md b/Solutions/TrendAI Vision One/docs/internal/test-deploy.md new file mode 100644 index 00000000000..861a1c3303c --- /dev/null +++ b/Solutions/TrendAI Vision One/docs/internal/test-deploy.md @@ -0,0 +1,93 @@ +# 🔒 INTERNAL — Test-deploy & publishing notes + +> **Audience: Trend Micro maintainers only.** +> This page documents the temporary test-deploy plumbing used **while the repository is private**. It references internal hosts and an internal storage account. +> +> **Before the repo goes public, this `internal/` folder should be removed (or the test-deploy section pruned)** and the README's "Test Deploy (Azure Storage-hosted…)" block deleted. See the [Go-Live Checklist](../../.github/GO_LIVE_CHECKLIST.md). + +--- + +## Why this exists + +The public "Deploy to Azure" buttons point at **GitHub raw URLs**. Those only work once the repo is **public** — the Azure Portal fetches the nested component templates anonymously, and GitHub raw returns 404 for private repos. + +So while the repo is private, we mirror the templates to a **public Azure Blob container** that the portal *can* read without auth, and use a second set of "Test Deploy" buttons that point at the blob URLs. + +``` +Private repo (templates/) ──publish-templates.sh──▶ Azure Blob (public read) ──▶ "Test Deploy" buttons work +``` + +Once the repo is public, the GitHub-raw buttons work directly and this mirror is no longer needed. + +--- + +## The storage account + +| | | +|---|---| +| Account | `trendaiccf45` | +| Container | `arm-templates` (public blob read) | +| Layout | `arm-templates/{workbench,oat}/…` and `arm-templates/assets/…` | + +The connector logos and the blob-hosted templates are served from here. Note the connector definitions currently reference the logo at `https://trendaiccf45.blob.core.windows.net/arm-templates/assets/trendai-logo.svg` — that URL must keep resolving (or be repointed to the GitHub raw asset) when this account is retired. + +--- + +## One-time setup (per maintainer) + +```bash +# Install Azure CLI +# macOS: brew install azure-cli +# Linux: https://learn.microsoft.com/cli/azure/install-azure-cli-linux + +az login +az account set --subscription "" +``` + +**Access required:** at least **Contributor** (or **Storage Account Key Operator Service Role**) on `trendaiccf45`, so `az storage account keys list` works. Data-plane-only access? Use a SAS token instead (the script accepts `AZURE_STORAGE_SAS_TOKEN`). + +--- + +## Publishing after you change templates + +Every time you edit anything under `templates/`, re-publish so the test-deploy buttons serve current code: + +```bash +export AZURE_STORAGE_KEY="$(az storage account keys list \ + --account-name trendaiccf45 \ + --query '[0].value' -o tsv)" + +./scripts/publish-templates.sh # both connectors +# or: ./scripts/publish-templates.sh workbench +# or: ./scripts/publish-templates.sh oat +``` + +What [scripts/publish-templates.sh](../../scripts/publish-templates.sh) does: + +1. Stages `templates//` into a temp dir. +2. **Rewrites the `baseUrl`** in `mainTemplate.json` from the GitHub-raw URL to the blob URL, so the nested component fetches resolve from the blob while private. +3. Uploads to `trendaiccf45/arm-templates//` with `no-cache` so the portal always gets the latest. +4. Also uploads `assets/`. + +**Auth precedence** in the script: `AZURE_STORAGE_KEY` → `AZURE_STORAGE_SAS_TOKEN` → `az login` (needs *Storage Blob Data Contributor*). + +> ⚠️ The script edits a staged copy, not your working tree — but it does `sed` the `baseUrl`. Don't commit a `mainTemplate.json` whose `baseUrl` points at the blob; the committed version must keep the **GitHub raw** URL for the public buttons. + +--- + +## Going public — what changes here + +When the repo flips to public ([Go-Live Checklist](../../.github/GO_LIVE_CHECKLIST.md)): + +1. The GitHub-raw "Deploy to Azure" buttons start working on their own. +2. Delete the **"Test Deploy (Azure Storage-hosted…)"** section from the [README](../../README.md). +3. Repoint or re-host the **logo** asset off `trendaiccf45` if you plan to retire the storage account. +4. Remove this `internal/` folder (or at least this page) so external readers don't see internal hosts. +5. Confirm `mainTemplate.json` `baseUrl` values point at the public GitHub raw path (they should already). + +--- + +## Related internal references + +- [Go-Live Checklist](../../.github/GO_LIVE_CHECKLIST.md) — full pre-public checklist (secret scans, branch protection, etc.) +- Trend Micro OpenSource Community Standards Policy (Confluence, internal) diff --git a/Solutions/TrendAI Vision One/functions/Parser-OAT.kql b/Solutions/TrendAI Vision One/functions/Parser-OAT.kql new file mode 100644 index 00000000000..f3e225089ff --- /dev/null +++ b/Solutions/TrendAI Vision One/functions/Parser-OAT.kql @@ -0,0 +1,36 @@ +// ════════════════════════════════════════════════════════════════════════════════ +// TrendMicro OAT - UNIVERSAL Parser: Works with OLD and NEW data +// ════════════════════════════════════════════════════════════════════════════════ +// +// PURPOSE: +// Universal parser that combines: +// - OLD data: TrendMicro_XDR_OAT_CL (legacy Azure Function connector) - AS-IS +// - NEW data: TrendMicro_XDR_OAT_V2_CL (CCF connector) - AS-IS (schema matches legacy) +// +// DEPLOYMENT: +// Create function named: TrendMicroOAT_Complete +// +// USAGE: +// TrendMicroOAT_Complete() +// | where detail_filterRiskLevel_s == "high" +// | project TimeGenerated, detail_endpointHostName_s, detail_objectCmd_s, detail_filterRiskLevel_s +// +// NOTE: +// Both tables have identical schemas, so we just union them. +// The source_table column is added to identify which table the data came from. +// +// ════════════════════════════════════════════════════════════════════════════════ + +union isfuzzy=true + // ═══════════════════════════════════════════════════════════════════════════ + // LEGACY DATA (Azure Function): Use AS-IS (already in correct format) + // ═══════════════════════════════════════════════════════════════════════════ + (TrendMicro_XDR_OAT_CL + | extend source_table = "legacy" + ), + // ═══════════════════════════════════════════════════════════════════════════ + // V2 DATA (CCF Connector): Use AS-IS (schema should match legacy) + // ═══════════════════════════════════════════════════════════════════════════ + (TrendMicro_XDR_OAT_V2_CL + | extend source_table = "ccf" + ) diff --git a/Solutions/TrendAI Vision One/functions/Parser-Workbench.kql b/Solutions/TrendAI Vision One/functions/Parser-Workbench.kql new file mode 100644 index 00000000000..0eb7efdc4a2 --- /dev/null +++ b/Solutions/TrendAI Vision One/functions/Parser-Workbench.kql @@ -0,0 +1,246 @@ +// ════════════════════════════════════════════════════════════════════════════════ +// TrendMicro Workbench - UNIVERSAL Parser: Works with OLD and NEW data +// ════════════════════════════════════════════════════════════════════════════════ +// +// PURPOSE: +// Universal parser that combines: +// - OLD data: TrendMicro_XDR_WORKBENCH_CL (legacy connector) - AS-IS +// - NEW data: TrendMicro_XDR_WORKBENCH_CCF_CL (CCF connector) - transformed to match legacy format +// +// DEPLOYMENT: +// Create function named: TrendMicroWorkbench_Complete +// +// USAGE: +// TrendMicroWorkbench_Complete() +// | where severity_s == "critical" +// | project TimeGenerated, workbenchId_s, FileName_s, IPAddress, HostHostName_s +// +// ════════════════════════════════════════════════════════════════════════════════ + +union isfuzzy=true + // ═══════════════════════════════════════════════════════════════════════════ + // LEGACY DATA (Azure Function): Use AS-IS (already in correct format) + // ═══════════════════════════════════════════════════════════════════════════ + (TrendMicro_XDR_WORKBENCH_CL), + // ═══════════════════════════════════════════════════════════════════════════ + // V2 DATA (CCF Connector): Transform to match legacy format using working parser logic + // ═══════════════════════════════════════════════════════════════════════════ + (TrendMicro_XDR_WORKBENCH_V2_CL + // Auto-detect format: use dynamic column if available, otherwise parse string column + | extend indicators_array = iff(isnull(indicators), parse_json(indicators_s), indicators) + | extend impactScope_parsed = iff(isnull(entities), parse_json(impactScope_s), dynamic(null)) + | extend entities_array = iff(isnull(entities), impactScope_parsed.entities, entities) + | extend matchedRules_array = iff(isnull(matchedRules), parse_json(matchedRules_s), matchedRules) + // Extract count fields from impactScope (only for old data) + | extend desktopCount_extracted = iff(isnull(entities), toint(impactScope_parsed.desktopCount), toint(desktopCount_d)) + | extend serverCount_extracted = iff(isnull(entities), toint(impactScope_parsed.serverCount), toint(serverCount_d)) + | extend accountCount_extracted = iff(isnull(entities), toint(impactScope_parsed.accountCount), toint(accountCount_d)) + | extend emailAddressCount_extracted = iff(isnull(entities), toint(impactScope_parsed.emailAddressCount), toint(emailAddressCount_d)) + // Step 1: Expand and extract indicators + | mv-expand indicator = indicators_array + | extend ind_type = tostring(indicator.type) + | extend ind_value = tostring(indicator.value) + | extend ind_field = tostring(indicator.field) + // Aggregate IOCs by workbenchId + | summarize + ProcessCommandLine_s = maxif(ind_value, ind_type == "command_line"), + FileName_s = maxif(ind_value, ind_type == "filename"), + FileHashValue_s = maxif(ind_value, ind_type in ("file_sha1", "file_sha256", "md5")), + DomainName_s = maxif(ind_value, ind_type == "domain"), + FileDirectory_s = maxif(ind_value, ind_type == "fullpath"), + IPAddress_extracted = maxif(ind_value, ind_type == "ip"), + URL_s = maxif(ind_value, ind_type == "url"), + RegistryKey_s = maxif(ind_value, ind_type == "registry_key"), + RegistryValue_s = maxif(ind_value, ind_type == "registry_value_data"), + RegistryValueName_s = maxif(ind_value, ind_type == "registry_value"), + MalwareName_s = maxif(ind_value, ind_type == "detection_name"), + entities_array = any(entities_array), + // Preserve extracted counts + desktopCount_extracted = any(desktopCount_extracted), + serverCount_extracted = any(serverCount_extracted), + accountCount_extracted = any(accountCount_extracted), + emailAddressCount_extracted = any(emailAddressCount_extracted), + // Preserve all columns + TimeGenerated = any(TimeGenerated), + SourceSystem = any(SourceSystem), + MG = any(MG), + ManagementGroupName = any(ManagementGroupName), + Computer = any(Computer), + RawData = any(RawData), + schemaVersion_s = any(schemaVersion_s), + investigationStatus_s = any(investigationStatus_s), + alertStatus_s = any(alertStatus_s), + investigationResult_s = any(investigationResult_s), + workbenchLink_s = any(workbenchLink_s), + alertProvider_s = any(alertProvider_s), + modelId_g = any(modelId_g), + modelId_s = any(modelId_s), + model_s = any(model_s), + workbenchName_s = any(workbenchName_s), + modelType_s = any(modelType_s), + priorityScore_d = any(priorityScore_d), + severity_s = any(severity_s), + createdTime_t = any(createdTime_t), + updatedTime_t = any(updatedTime_t), + alertTriggerTimestamp_t = any(alertTriggerTimestamp_t), + workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t), + incidentId_s = any(incidentId_s), + description_s = any(description_s), + desktopCount_d = any(desktopCount_d), + serverCount_d = any(serverCount_d), + accountCount_d = any(accountCount_d), + emailAddressCount_d = any(emailAddressCount_d), + indicators_s = any(indicators_s), + impactScope_s = any(impactScope_s), + impactScope_Summary_s = any(impactScope_Summary_s), + matchedRules_s = any(matchedRules_s), + xdrCustomerID_g = any(xdrCustomerID_g), + TenantId = any(TenantId), + Type = any(Type), + _ResourceId = any(_ResourceId) + by workbenchId_s + // Step 2: Expand and extract entities + | mv-expand entity = entities_array + | extend ent_type = tostring(entity.entityType) + | extend ent_value = entity.entityValue + | extend ent_value_str = tostring(entity.entityValue) + | extend ent_value_name = tostring(entity.entityValue.name) + // Aggregate entities by workbenchId + | summarize + HostHostName_s = maxif(ent_value_name, ent_type == "host"), + UserAccountFull = maxif(ent_value_str, ent_type == "account" and ent_value_str contains "\\"), + MailboxPrimaryAddress_s = maxif(ent_value_str, ent_type == "emailAddress"), + // Keep IOCs from previous step + ProcessCommandLine_s = any(ProcessCommandLine_s), + FileName_s = any(FileName_s), + FileHashValue_s = any(FileHashValue_s), + DomainName_s = any(DomainName_s), + FileDirectory_s = any(FileDirectory_s), + IPAddress_extracted = any(IPAddress_extracted), + URL_s = any(URL_s), + RegistryKey_s = any(RegistryKey_s), + RegistryValue_s = any(RegistryValue_s), + RegistryValueName_s = any(RegistryValueName_s), + MalwareName_s = any(MalwareName_s), + // Keep extracted counts + desktopCount_extracted = any(desktopCount_extracted), + serverCount_extracted = any(serverCount_extracted), + accountCount_extracted = any(accountCount_extracted), + emailAddressCount_extracted = any(emailAddressCount_extracted), + // Keep all other columns + TimeGenerated = any(TimeGenerated), + SourceSystem = any(SourceSystem), + MG = any(MG), + ManagementGroupName = any(ManagementGroupName), + Computer = any(Computer), + RawData = any(RawData), + schemaVersion_s = any(schemaVersion_s), + investigationStatus_s = any(investigationStatus_s), + alertStatus_s = any(alertStatus_s), + investigationResult_s = any(investigationResult_s), + workbenchLink_s = any(workbenchLink_s), + alertProvider_s = any(alertProvider_s), + modelId_g = any(modelId_g), + modelId_s = any(modelId_s), + model_s = any(model_s), + workbenchName_s = any(workbenchName_s), + modelType_s = any(modelType_s), + priorityScore_d = any(priorityScore_d), + severity_s = any(severity_s), + createdTime_t = any(createdTime_t), + updatedTime_t = any(updatedTime_t), + alertTriggerTimestamp_t = any(alertTriggerTimestamp_t), + workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t), + incidentId_s = any(incidentId_s), + description_s = any(description_s), + desktopCount_d = any(desktopCount_d), + serverCount_d = any(serverCount_d), + accountCount_d = any(accountCount_d), + emailAddressCount_d = any(emailAddressCount_d), + indicators_s = any(indicators_s), + impactScope_s = any(impactScope_s), + impactScope_Summary_s = any(impactScope_Summary_s), + matchedRules_s = any(matchedRules_s), + xdrCustomerID_g = any(xdrCustomerID_g), + TenantId = any(TenantId), + Type = any(Type), + _ResourceId = any(_ResourceId) + by workbenchId_s + // Step 3: Parse domain\username and apply defaults + | extend UserAccountNTDomain_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, "\\")[0], "[]") + | extend UserAccountName_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, "\\")[1], "[]") + // Apply backward-compatible empty value defaults + | extend + FileName_s = coalesce(FileName_s, "[]"), + FileHashValue_s = coalesce(FileHashValue_s, "[]"), + DomainName_s = coalesce(DomainName_s, "[]"), + FileDirectory_s = coalesce(FileDirectory_s, "[]"), + IPAddress = coalesce(IPAddress_extracted, "[]"), + URL_s = coalesce(URL_s, "[]"), + HostHostName_s = coalesce(HostHostName_s, "[]"), + ProcessCommandLine_s = coalesce(ProcessCommandLine_s, "[]"), + RegistryKey_s = coalesce(RegistryKey_s, "[]"), + RegistryValue_s = coalesce(RegistryValue_s, "[]"), + RegistryValueName_s = coalesce(RegistryValueName_s, "[]"), + MailboxPrimaryAddress_s = coalesce(MailboxPrimaryAddress_s, "[]"), + MalwareName_s = coalesce(MalwareName_s, "[]"), + // Apply count defaults + desktopCount_d = coalesce(desktopCount_extracted, 0), + serverCount_d = coalesce(serverCount_extracted, 0), + accountCount_d = coalesce(accountCount_extracted, 0), + emailAddressCount_d = coalesce(emailAddressCount_extracted, 0) + | project // Final projection with exact backward-compatible schema + TimeGenerated, + SourceSystem, + MG, + ManagementGroupName, + Computer, + RawData, + FileName_s, + FileHashValue_s, + DomainName_s, + FileDirectory_s, + IPAddress, + URL_s, + HostHostName_s, + ProcessCommandLine_s, + RegistryKey_s, + RegistryValue_s, + RegistryValueName_s, + UserAccountNTDomain_s, + UserAccountName_s, + alertProvider_s, + alertTriggerTimestamp_t, + createdTime_t, + description_s, + impactScope_s, + impactScope_Summary_s, + indicators_s, + investigationStatus_s, + matchedRules_s, + model_s, + modelId_g, + modelId_s, + priorityScore_d, + severity_s, + updatedTime_t, + workbenchCompleteTimestamp_t, + workbenchId_s, + workbenchLink_s, + workbenchName_s, + xdrCustomerID_g, + MailboxPrimaryAddress_s, + MalwareName_s, + schemaVersion_s, + alertStatus_s, + investigationResult_s, + modelType_s, + incidentId_s, + desktopCount_d, + serverCount_d, + accountCount_d, + emailAddressCount_d, + Type, + TenantId, + _ResourceId + ) diff --git a/Solutions/TrendAI Vision One/scripts/publish-templates.sh b/Solutions/TrendAI Vision One/scripts/publish-templates.sh new file mode 100755 index 00000000000..1d45190aed2 --- /dev/null +++ b/Solutions/TrendAI Vision One/scripts/publish-templates.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Publish ARM templates to the Azure Blob container that backs the +# "Test Deploy" buttons in README.md (used while the repo is private). +# +# What it does: +# 1. Stages templates/ into a temp dir +# 2. Rewrites the `baseUrl` variable in each mainTemplate.json from the +# GitHub raw URL -> the Azure blob URL (so nested component fetches +# work while the repo is private) +# 3. Uploads the staged files to //{workbench,oat} +# +# Usage: +# ./scripts/publish-templates.sh # upload workbench + oat +# ./scripts/publish-templates.sh workbench # upload only workbench +# ./scripts/publish-templates.sh oat # upload only oat +# +# Auth (in priority order): +# AZURE_STORAGE_KEY -- account key +# AZURE_STORAGE_SAS_TOKEN -- SAS token +# else falls back to `az login` (needs Storage Blob Data Contributor) + +set -euo pipefail + +ACCOUNT="${AZURE_STORAGE_ACCOUNT:-trendaiccf45}" +CONTAINER="${AZURE_STORAGE_CONTAINER:-arm-templates}" +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SRC="$ROOT/templates" + +GITHUB_BASE="https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates" +BLOB_BASE="https://${ACCOUNT}.blob.core.windows.net/${CONTAINER}" + +TARGETS=("$@") +if [ ${#TARGETS[@]} -eq 0 ]; then + TARGETS=(workbench oat) +fi + +AUTH_ARGS=(--auth-mode login) +if [ -n "${AZURE_STORAGE_KEY:-}" ]; then + AUTH_ARGS=(--account-key "$AZURE_STORAGE_KEY") +elif [ -n "${AZURE_STORAGE_SAS_TOKEN:-}" ]; then + AUTH_ARGS=(--sas-token "$AZURE_STORAGE_SAS_TOKEN") +fi + +STAGE="$(mktemp -d -t trendai-publish.XXXXXX)" +trap 'rm -rf "$STAGE"' EXIT + +for t in "${TARGETS[@]}"; do + if [ ! -d "$SRC/$t" ]; then + echo "skip: $SRC/$t not found" >&2 + continue + fi + + echo "==> staging templates/$t" + cp -R "$SRC/$t" "$STAGE/$t" + + MAIN="$STAGE/$t/mainTemplate.json" + if [ -f "$MAIN" ]; then + # Rewrite GitHub raw baseUrl -> Azure blob baseUrl for THIS connector's components. + # sed -i'' '' for BSD/macOS compatibility. + sed -i'' -e "s|${GITHUB_BASE}/${t}/components|${BLOB_BASE}/${t}/components|g" "$MAIN" + echo " rewrote baseUrl in $t/mainTemplate.json" + fi + + echo "==> uploading $t -> $ACCOUNT/$CONTAINER/$t" + az storage blob upload-batch \ + --account-name "$ACCOUNT" \ + --destination "$CONTAINER" \ + --destination-path "$t" \ + --source "$STAGE/$t" \ + --overwrite \ + "${AUTH_ARGS[@]}" >/dev/null +done + +echo "done. Test-deploy URLs in README.md now point to the latest code." diff --git a/Solutions/TrendAI Vision One/templates/ARCHITECTURE.md b/Solutions/TrendAI Vision One/templates/ARCHITECTURE.md new file mode 100644 index 00000000000..21937893c4c --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/ARCHITECTURE.md @@ -0,0 +1,402 @@ +# Sentinel Connector Architecture + +This document describes the modular architecture used for both **Workbench** and **OAT** connectors. + +## Overview + +Both connectors follow Microsoft's recommended **Codeless Connector Platform (CCP)** pattern with modular components, enabling: + +- ✅ Single-click deployment via "Deploy to Azure" button +- ✅ Independent component testing and updates +- ✅ Proper dependency management +- ✅ Custom Azure Portal deployment UI + +## Directory Structure + +``` +templates/ +├── workbench/ # Workbench Alerts Connector +│ ├── mainTemplate.json # Orchestrator +│ ├── createUiDefinition.json # Custom Portal UI +│ └── components/ +│ ├── sentinel-solution.json # Enables Sentinel +│ ├── table.json # 56 columns +│ ├── dce.json # Data Collection Endpoint +│ ├── dcr.json # Data Collection Rule + transform +│ ├── connector-definition.json # Portal UI definition +│ └── parser-function.json # KQL parser for IOC extraction +│ +├── oat/ # OAT Connector +│ ├── mainTemplate.json # Orchestrator +│ ├── createUiDefinition.json # Custom Portal UI +│ └── components/ +│ ├── sentinel-solution.json # Enables Sentinel +│ ├── table.json # 139 columns +│ ├── dce.json # Data Collection Endpoint +│ ├── dcr.json # Data Collection Rule + transform +│ ├── connector-definition.json # Portal UI definition +│ └── parser-function.json # Universal parser (old + new OAT data) +│ +└── legacy/ # Archived old templates +``` + +## Component Architecture + +### 1. mainTemplate.json (Orchestrator) + +**Purpose**: Entry point for "Deploy to Azure" button that orchestrates all component deployments. + +**How it works**: +- Uses nested deployments to call each component template +- Components hosted on GitHub (linked templates) +- Manages dependency chain automatically +- Passes outputs between components + +**Key sections**: +```json +{ + "variables": { + "baseUrl": "https://raw.githubusercontent.com/trendmicro/..." + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "properties": { + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/sentinel-solution.json')]" + } + } + } + ] +} +``` + +### 2. createUiDefinition.json (Portal UI) + +**Purpose**: Custom deployment experience in Azure Portal. + +**Features**: +- Workspace dropdown (auto-populated from subscription) +- Region selector for Trend Vision One +- Validation and tooltips +- Post-deployment instructions + +**User experience**: +1. User clicks "Deploy to Azure" +2. Portal loads this UI definition +3. User fills simple form (workspace + region) +4. Deployment starts automatically + +### 3. Components + +#### A. sentinel-solution.json + +Deploys Microsoft Sentinel solution to enable Sentinel on workspace. + +**Resource**: `Microsoft.OperationsManagement/solutions` + +**Outputs**: `solutionId` + +#### B. table.json + +Creates custom log table with schema. + +**Resource**: `Microsoft.OperationalInsights/workspaces/tables` + +**Schemas**: +- **Workbench**: 56 columns (core fields + IOCs + dynamic columns) +- **OAT**: 139 columns (all detail_* fields flattened) + +**Outputs**: `tableName`, `tableId` + +#### C. dce.json + +Creates Data Collection Endpoint for log ingestion. + +**Resource**: `Microsoft.Insights/dataCollectionEndpoints` + +**Outputs**: `dceId`, `dceName`, `dceEndpoint` + +#### D. dcr.json + +Creates Data Collection Rule with transformation. + +**Resource**: `Microsoft.Insights/dataCollectionRules` + +**Key features**: +- Stream declaration (input schema from API) +- TransformKql (maps API response → table schema) +- Routes data to Log Analytics workspace + +**Workbench transform example**: +```kql +source +| extend TimeGenerated = todatetime(createdDateTime) +| extend workbenchId_s = tostring(id) +| extend severity_s = tostring(severity) +| extend indicators = indicators +| extend entities = impactScope.entities +``` + +**OAT transform** (very large): +- Flattens entire `detail` dynamic object +- 130+ field mappings +- Converts Unix timestamps to datetime + +**Outputs**: `dcrId`, `dcrImmutableId`, `streamName` + +#### E. connector-definition.json + +Creates connector UI in Sentinel portal. + +**Resource**: `Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions` + +**Kind**: `Customizable` + +**Includes**: +- UI configuration (title, description, instructions) +- Sample queries +- Connectivity criteria +- Graph queries + +**Note**: Connection details (API endpoint, auth, paging) are configured manually in the Portal after deployment. + +**Outputs**: `connectorId` + +#### F. parser-function.json (Workbench and OAT) + +Deploys a KQL saved function. Both connectors ship one, and both are **universal** — +they auto-detect the data shape and return one stable schema across old (legacy V1 +Azure Function) and new (CCF) data. + +**Resource**: `Microsoft.OperationalInsights/workspaces/savedSearches` + +**Workbench function**: `TrendMicroWorkbench_Complete()` — extracts IOCs from the dynamic +columns (indicators, entities, matchedRules), falling back to the stringified `*_s` +columns for old data. + +```kql +TrendMicroWorkbench_Complete() +| where severity_s == "critical" +| where isnotempty(FileHashValue_s) +``` + +**OAT function**: `TrendMicroOAT_Complete()` — returns the full flat `detail_*` schema, +preferring the typed flat column and falling back to re-deriving each field from the +detail payload (`detail` dynamic, `detail_s` string, or `RawData`). Adds convenience +columns `mitreTacticIds_s` / `mitreTechniqueIds_s`. + +```kql +TrendMicroOAT_Complete() +| where detail_filterRiskLevel_s == "high" +| project TimeGenerated, detail_endpointHostName_s, detail_processCmd_s +``` + +**Outputs**: `functionName` + +## Deployment Flow + +``` +User clicks "Deploy to Azure" button + ↓ +Azure Portal loads: + - mainTemplate.json + - createUiDefinition.json + ↓ +User fills form: + - Selects workspace (dropdown) + - Selects Trend region (dropdown) + ↓ +Deployment begins: + 1. sentinel-solution ✓ + 2. table ✓ (depends on #1) + 3. dce ✓ (parallel with #2) + 4. dcr ✓ (depends on #2, #3) + 5. connector-definition ✓ (depends on #1, #4) + 6. parser-function ✓ (depends on #2; Workbench + OAT) + ↓ +Deployment complete (3-5 min) + ↓ +User manually connects in Portal: + - Sentinel → Data connectors + - Enter API token + - Click Connect +``` + +## Dependency Chain + +### Workbench + +``` +sentinel-solution + ↓ +table ───────┐ + ↓ │ + ↓ dce │ + ↓ ↓ │ + └──→ dcr │ + ↓ │ +connector-definition + ↓ + parser-function +``` + +### OAT + +``` +sentinel-solution + ↓ +table ───────┐ + ↓ │ + ↓ dce │ + ↓ ↓ │ + └──→ dcr │ + ↓ │ +connector-definition + ↓ + parser-function +``` + +## Comparison: Workbench vs OAT + +| Aspect | Workbench | OAT | +|--------|-----------|-----| +| Components | 6 | 6 | +| Table Columns | 56 | 139 | +| Input Stream Fields | 19 | 9 | +| Transform Complexity | Moderate | Very High | +| Dynamic Columns | Yes (indicators, entities, matchedRules) | No (all flattened) | +| Parser Function | Yes (IOC extraction, universal old+new) | Yes (universal old+new normalizer) | +| API Endpoint | /v3.0/workbench/alerts | /v3.0/oat/detections | +| Data Volume | Medium | High | + +## Benefits of Modular Architecture + +### 1. Maintainability + +Update individual components without touching others: +- Need to change DCR transform? Edit `dcr.json` only +- Need to add table columns? Edit `table.json` only +- Changes auto-deploy on next "Deploy to Azure" click + +### 2. Testability + +Test each component independently: +```bash +az deployment group create \ + --template-file templates/workbench/components/table.json \ + --parameters workspace=test-ws workspace-location=eastus +``` + +### 3. Reusability + +Components can be reused in other solutions: +- Copy `dce.json` + `dcr.json` for any custom log ingestion +- Reuse `sentinel-solution.json` for any Sentinel deployment +- Pattern works for any Trend Vision One API + +### 4. Microsoft Best Practices + +Follows official patterns: +- [SentinelOne CCP Example](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/SentinelOne/Data%20Connectors/SentinelOne_ccp) +- [Deploy to Azure Button Guide](https://learn.microsoft.com/azure/azure-resource-manager/templates/deploy-to-azure-button) +- [CCP Documentation](https://learn.microsoft.com/azure/sentinel/create-codeless-connector) + +## Technical Deep Dives + +### Transform KQL Examples + +**Workbench - Extract IOCs from indicators array**: +```kql +source +| extend TimeGenerated = todatetime(createdDateTime) +| extend indicators_dynamic = indicators +| extend indicators_s = tostring(indicators) +| extend indicators = indicators_dynamic +``` + +**OAT - Flatten detail object**: +```kql +source +| extend d = detail +| extend detail_processCmd_s = tostring(d.processCmd) +| extend detail_processFileHashSha256_s = tostring(d.processFileHashSha256) +| extend detail_processPid_d = toreal(d.processPid) +| extend detail_firstSeen_t = todatetime(datetime(1970-01-01) + tolong(d.firstSeen) * 1ms) +... (130+ more fields) +``` + +### Linked Template Pattern + +mainTemplate.json references components via GitHub URLs: +```json +{ + "templateLink": { + "uri": "https://raw.githubusercontent.com/trendmicro/.../table.json", + "contentVersion": "1.0.0.0" + } +} +``` + +**Benefits**: +- Components update automatically when repo updates +- No need to merge everything into one massive file +- Version control per component + +### createUiDefinition Schema + +```json +{ + "basics": [ + { + "name": "workspaceSelector", + "type": "Microsoft.Solutions.ResourceSelector", + "resourceType": "Microsoft.OperationalInsights/workspaces" + } + ], + "steps": [ + { + "name": "trendConfig", + "elements": [ + { + "name": "trendaiRegion", + "type": "Microsoft.Common.DropDown", + "allowedValues": ["US", "UK", "SG", "CA", "JP"] + } + ] + } + ] +} +``` + +## Migration from Legacy + +If you deployed old templates (templates/legacy/), you can: + +### Option 1: Keep Existing +- Old deployments continue to work +- No action required + +### Option 2: Fresh Deployment +- Deploy modular templates to new workspace +- Migrate data if needed +- Decommission old deployment + +### Option 3: In-Place Upgrade +1. Delete old connector definition +2. Deploy modular components +3. Reconnect with API token + +**Recommendation**: Option 2 (fresh deployment to new workspace) is safest for production. + +## Resources + +- [Microsoft Sentinel Documentation](https://learn.microsoft.com/azure/sentinel) +- [ARM Template Reference](https://learn.microsoft.com/azure/templates) +- [Data Collection Rules](https://learn.microsoft.com/azure/azure-monitor/essentials/data-collection-rule-overview) +- [Trend Vision One API](https://automation.trendmicro.com/xdr/api-v3) + +--- + +**Architecture Version**: 2.0 +**Last Updated**: May 2026 diff --git a/Solutions/TrendAI Vision One/templates/legacy/README.md b/Solutions/TrendAI Vision One/templates/legacy/README.md new file mode 100644 index 00000000000..7a748e50ba5 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/README.md @@ -0,0 +1,35 @@ +# Legacy Templates + +This folder contains legacy/archived templates for historical reference. + +## Contents + +### Workbench Templates +- `arm-template-workbench-compatibleSchema.json` - Old Workbench connector (compatible schema) +- `arm-template-workbench-newSchema.json` - Old Workbench connector (new schema) +- `arm-template-workbench-microsoft-pattern.json` - Monolithic Workbench template +- `deploy-parser-function.json` - Standalone parser function deployment + +### OAT Templates +- `arm-template-oat-compatibleSchema.json` - Old OAT connector (compatible schema) +- `arm-template-oat-newSchema.json` - Old OAT connector (new schema) + +## Notice + +⚠️ **These templates are deprecated** + +Please use the new modular templates: +- **Workbench**: `templates/workbench/` +- **OAT**: `templates/oat/` + +Both follow Microsoft's recommended modular architecture pattern with Deploy to Azure buttons. + +## Migration + +If you have deployed using these legacy templates, you can: + +1. Keep existing deployments (they will continue to work) +2. Deploy new modular templates to a different workspace +3. Migrate by deleting old resources and deploying new modular solution + +For migration assistance, please open an issue in the repository. diff --git a/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-compatibleSchema.json b/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-compatibleSchema.json new file mode 100644 index 00000000000..c5e69fcc01a --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-compatibleSchema.json @@ -0,0 +1,926 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "2.0.2.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Workspace Azure region" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "US", + "allowedValues": [ + "UK", + "US", + "SG", + "CA", + "JP" + ], + "metadata": { + "description": "Trend Vision One region" + } + }, + "apikey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Trend Micro Vision One API Key (Bearer token without 'Bearer' prefix)" + } + }, + "oatFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter for OAT API. Example: (riskLevel eq 'high'). Leave empty for no filter." + } + } + }, + "variables": { + "tableName": "TrendMicro_XDR_OAT_V2_CL", + "dceName": "TrendMicro-XDR-OAT-DCE", + "dcrName": "TrendMicro-XDR-OAT-DCR", + "connectorId": "TrendMicro_XDR_OAT", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + }, + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[concat(parameters('workspace'), '/', variables('tableName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "schema": { + "name": "[variables('tableName')]", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "SourceSystem", + "type": "string" + }, + { + "name": "Computer", + "type": "string" + }, + { + "name": "RawData", + "type": "string" + }, + { + "name": "detectionTime_t", + "type": "datetime" + }, + { + "name": "entityType_s", + "type": "string" + }, + { + "name": "entityName_s", + "type": "string" + }, + { + "name": "filters_s", + "type": "string" + }, + { + "name": "endpoint_ips_s", + "type": "string" + }, + { + "name": "endpoint_name_s", + "type": "string" + }, + { + "name": "endpoint_guid_g", + "type": "string" + }, + { + "name": "xdrCustomerId_g", + "type": "string" + }, + { + "name": "detail_endpointGuid_g", + "type": "string" + }, + { + "name": "detail_eventId_s", + "type": "string" + }, + { + "name": "detail_eventSubId_s", + "type": "string" + }, + { + "name": "detail_firstSeen_t", + "type": "datetime" + }, + { + "name": "detail_lastSeen_t", + "type": "datetime" + }, + { + "name": "detail_logonUser_s", + "type": "string" + }, + { + "name": "detail_objectCmd_s", + "type": "string" + }, + { + "name": "detail_objectFileCreation_d", + "type": "real" + }, + { + "name": "detail_objectFileHashSha256_s", + "type": "string" + }, + { + "name": "detail_objectFileModifiedTime_d", + "type": "real" + }, + { + "name": "detail_objectFileSize_d", + "type": "real" + }, + { + "name": "detail_objectLaunchTime_d", + "type": "real" + }, + { + "name": "detail_objectName_s", + "type": "string" + }, + { + "name": "detail_objectRunAsLocalAccount_b", + "type": "boolean" + }, + { + "name": "detail_objectSigner_s", + "type": "string" + }, + { + "name": "detail_objectSignerValid_s", + "type": "string" + }, + { + "name": "detail_objectTrueType_d", + "type": "real" + }, + { + "name": "detail_objectUser_s", + "type": "string" + }, + { + "name": "detail_objectUserDomain_s", + "type": "string" + }, + { + "name": "detail_osName_s", + "type": "string" + }, + { + "name": "detail_osType_s", + "type": "string" + }, + { + "name": "detail_osVer_s", + "type": "string" + }, + { + "name": "detail_parentCmd_s", + "type": "string" + }, + { + "name": "detail_parentFileCreation_d", + "type": "real" + }, + { + "name": "detail_parentFileHashSha1_s", + "type": "string" + }, + { + "name": "detail_parentFileHashSha256_s", + "type": "string" + }, + { + "name": "detail_parentFileModifiedTime_d", + "type": "real" + }, + { + "name": "detail_parentFilePath_s", + "type": "string" + }, + { + "name": "detail_parentFileSize_d", + "type": "real" + }, + { + "name": "detail_parentLaunchTime_d", + "type": "real" + }, + { + "name": "detail_parentName_s", + "type": "string" + }, + { + "name": "detail_parentTrueType_d", + "type": "real" + }, + { + "name": "detail_parentUser_s", + "type": "string" + }, + { + "name": "detail_parentUserDomain_s", + "type": "string" + }, + { + "name": "detail_plang_d", + "type": "real" + }, + { + "name": "detail_processCmd_s", + "type": "string" + }, + { + "name": "detail_processFileCreation_d", + "type": "real" + }, + { + "name": "detail_processFileHashSha1_s", + "type": "string" + }, + { + "name": "detail_processFileHashSha256_s", + "type": "string" + }, + { + "name": "detail_processFileModifiedTime_d", + "type": "real" + }, + { + "name": "detail_processFilePath_s", + "type": "string" + }, + { + "name": "detail_processFileSize_d", + "type": "real" + }, + { + "name": "detail_processLaunchTime_d", + "type": "real" + }, + { + "name": "detail_processPid_d", + "type": "real" + }, + { + "name": "detail_processSigner_s", + "type": "string" + }, + { + "name": "detail_processSignerValid_s", + "type": "string" + }, + { + "name": "detail_processTrueType_d", + "type": "real" + }, + { + "name": "detail_processUser_s", + "type": "string" + }, + { + "name": "detail_processUserDomain_s", + "type": "string" + }, + { + "name": "detail_timezone_s", + "type": "string" + }, + { + "name": "detail_userDomain_s", + "type": "string" + }, + { + "name": "detail_objectAppName_s", + "type": "string" + }, + { + "name": "detail_objectContentName_s", + "type": "string" + }, + { + "name": "detail_objectFirstSeen_d", + "type": "real" + }, + { + "name": "detail_objectLastSeen_d", + "type": "real" + }, + { + "name": "detail_objectRawDataStr_s", + "type": "string" + }, + { + "name": "detail_parentSigner_s", + "type": "string" + }, + { + "name": "detail_parentSignerValid_s", + "type": "string" + }, + { + "name": "detail_objectSubTrueType_d", + "type": "real" + }, + { + "name": "detail_hostName_s", + "type": "string" + }, + { + "name": "detail_objectIps_s", + "type": "string" + }, + { + "name": "detail_srcFirstSeen_d", + "type": "real" + }, + { + "name": "detail_srcLastSeen_d", + "type": "real" + }, + { + "name": "detail_actResult_s", + "type": "string" + }, + { + "name": "detail_channel_s", + "type": "string" + }, + { + "name": "detail_domainName_s", + "type": "string" + }, + { + "name": "detail_endpointMacAddress_s", + "type": "string" + }, + { + "name": "detail_eventSubName_s", + "type": "string" + }, + { + "name": "detail_firstAct_s", + "type": "string" + }, + { + "name": "detail_firstActResult_s", + "type": "string" + }, + { + "name": "detail_mDevice_s", + "type": "string" + }, + { + "name": "detail_malDst_s", + "type": "string" + }, + { + "name": "detail_malName_s", + "type": "string" + }, + { + "name": "detail_malSubType_s", + "type": "string" + }, + { + "name": "detail_objectFileHashSha1_s", + "type": "string" + }, + { + "name": "detail_objectFileName_s", + "type": "string" + }, + { + "name": "detail_objectFilePath_s", + "type": "string" + }, + { + "name": "detail_objectType_s", + "type": "string" + }, + { + "name": "detail_scanType_s", + "type": "string" + }, + { + "name": "detail_secondAct_s", + "type": "string" + }, + { + "name": "detail_secondActResult_s", + "type": "string" + }, + { + "name": "detail_act_s", + "type": "string" + }, + { + "name": "detail_aggregatedCount_d", + "type": "real" + }, + { + "name": "detail_app_s", + "type": "string" + }, + { + "name": "detail_appGroup_s", + "type": "string" + }, + { + "name": "detail_aptRelated_s", + "type": "string" + }, + { + "name": "detail_clientFlag_s", + "type": "string" + }, + { + "name": "detail_detectionType_s", + "type": "string" + }, + { + "name": "detail_deviceDirection_s", + "type": "string" + }, + { + "name": "detail_deviceGUID_g", + "type": "string" + }, + { + "name": "detail_deviceMacAddress_s", + "type": "string" + }, + { + "name": "detail_dhost_s", + "type": "string" + }, + { + "name": "detail_dmac_s", + "type": "string" + }, + { + "name": "detail_dpt_d", + "type": "real" + }, + { + "name": "detail_dst_s", + "type": "string" + }, + { + "name": "detail_dstGroup_s", + "type": "string" + }, + { + "name": "detail_dstZone_s", + "type": "string" + }, + { + "name": "detail_dvchost_s", + "type": "string" + }, + { + "name": "detail_eventId_d", + "type": "real" + }, + { + "name": "detail_eventName_s", + "type": "string" + }, + { + "name": "detail_eventSourceType_s", + "type": "string" + }, + { + "name": "detail_eventTime_d", + "type": "real" + }, + { + "name": "detail_fileExt_s", + "type": "string" + }, + { + "name": "detail_fileHash_s", + "type": "string" + }, + { + "name": "detail_fileName_s", + "type": "string" + }, + { + "name": "detail_filePath_s", + "type": "string" + }, + { + "name": "detail_filePathName_s", + "type": "string" + }, + { + "name": "detail_fileSize_d", + "type": "real" + }, + { + "name": "detail_filterRiskLevel_s", + "type": "string" + }, + { + "name": "detail_fullPath_s", + "type": "string" + }, + { + "name": "detail_hostSeverity_d", + "type": "real" + }, + { + "name": "detail_interestedGroup_s", + "type": "string" + }, + { + "name": "detail_interestedHost_s", + "type": "string" + }, + { + "name": "detail_interestedIp_s", + "type": "string" + }, + { + "name": "detail_malType_s", + "type": "string" + }, + { + "name": "detail_malTypeGroup_s", + "type": "string" + }, + { + "name": "detail_pAttackPhase_s", + "type": "string" + }, + { + "name": "detail_pComp_s", + "type": "string" + }, + { + "name": "detail_peerGroup_s", + "type": "string" + }, + { + "name": "detail_peerHost_s", + "type": "string" + }, + { + "name": "detail_peerIp_s", + "type": "string" + }, + { + "name": "detail_pname_s", + "type": "string" + }, + { + "name": "detail_remarks_s", + "type": "string" + }, + { + "name": "detail_rt_t", + "type": "datetime" + }, + { + "name": "detail_rtHour_d", + "type": "real" + }, + { + "name": "detail_ruleId_d", + "type": "real" + }, + { + "name": "detail_ruleName_s", + "type": "string" + }, + { + "name": "detail_senderIp_s", + "type": "string" + }, + { + "name": "detail_severity_d", + "type": "real" + }, + { + "name": "detail_shost_s", + "type": "string" + }, + { + "name": "detail_smac_s", + "type": "string" + }, + { + "name": "detail_spt_d", + "type": "real" + }, + { + "name": "detail_src_s", + "type": "string" + }, + { + "name": "detail_srcGroup_s", + "type": "string" + }, + { + "name": "detail_srcZone_s", + "type": "string" + }, + { + "name": "detail_tags_s", + "type": "string" + }, + { + "name": "detail_threatType_s", + "type": "string" + }, + { + "name": "detail_uuid_g", + "type": "string" + }, + { + "name": "detail_cat_d", + "type": "real" + }, + { + "name": "detail_endpointGUID_g", + "type": "string" + }, + { + "name": "detail_endpointHostName_s", + "type": "string" + }, + { + "name": "detail_endpointIp_s", + "type": "string" + }, + { + "name": "detail_processName_s", + "type": "string" + }, + { + "name": "detail_proto_s", + "type": "string" + } + ] + } + } + }, + { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dceName')]", + "location": "[parameters('workspace-location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + }, + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dcrName')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]", + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]" + ], + "properties": { + "dataCollectionEndpointId": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]", + "streamDeclarations": { + "Custom-TrendMicro_XDR_OAT_V2_CL": { + "columns": [ + { + "name": "source", + "type": "string" + }, + { + "name": "uuid", + "type": "string" + }, + { + "name": "detectedDateTime", + "type": "datetime" + }, + { + "name": "ingestedDateTime", + "type": "datetime" + }, + { + "name": "entityType", + "type": "string" + }, + { + "name": "entityName", + "type": "string" + }, + { + "name": "endpoint", + "type": "dynamic" + }, + { + "name": "filters", + "type": "dynamic" + }, + { + "name": "detail", + "type": "dynamic" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-TrendMicro_XDR_OAT_V2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source | extend d = detail | extend TimeGenerated = detectedDateTime, SourceSystem = 'RestAPI', Computer = '', RawData = tostring(detail), detectionTime_t = todatetime(detectedDateTime), entityType_s = tostring(entityType), entityName_s = tostring(entityName), filters_s = tostring(filters), endpoint_ips_s = tostring(endpoint.ips), endpoint_name_s = tostring(endpoint.endpointName), endpoint_guid_g = tostring(endpoint.agentGuid), xdrCustomerId_g = '', detail_endpointGuid_g = tostring(d.endpointGuid), detail_eventId_s = tostring(d.eventId), detail_eventSubId_s = tostring(d.eventSubId), detail_firstSeen_t = todatetime(datetime(1970-01-01) + tolong(d.firstSeen) * 1ms), detail_lastSeen_t = todatetime(datetime(1970-01-01) + tolong(d.lastSeen) * 1ms), detail_logonUser_s = tostring(d.logonUser), detail_objectCmd_s = tostring(d.objectCmd), detail_objectFileCreation_d = toreal(d.objectFileCreation), detail_objectFileHashSha256_s = tostring(d.objectFileHashSha256), detail_objectFileModifiedTime_d = toreal(d.objectFileModifiedTime), detail_objectFileSize_d = toreal(d.objectFileSize), detail_objectLaunchTime_d = toreal(d.objectLaunchTime), detail_objectName_s = tostring(d.objectName), detail_objectRunAsLocalAccount_b = tobool(d.objectRunAsLocalAccount), detail_objectSigner_s = tostring(d.objectSigner), detail_objectSignerValid_s = tostring(d.objectSignerValid), detail_objectTrueType_d = toreal(d.objectTrueType), detail_objectUser_s = tostring(d.objectUser), detail_objectUserDomain_s = tostring(d.objectUserDomain), detail_osName_s = tostring(d.osName), detail_osType_s = tostring(d.osType), detail_osVer_s = tostring(d.osVer), detail_parentCmd_s = tostring(d.parentCmd), detail_parentFileCreation_d = toreal(d.parentFileCreation), detail_parentFileHashSha1_s = tostring(d.parentFileHashSha1), detail_parentFileHashSha256_s = tostring(d.parentFileHashSha256), detail_parentFileModifiedTime_d = toreal(d.parentFileModifiedTime), detail_parentFilePath_s = tostring(d.parentFilePath), detail_parentFileSize_d = toreal(d.parentFileSize), detail_parentLaunchTime_d = toreal(d.parentLaunchTime), detail_parentName_s = tostring(d.parentName), detail_parentTrueType_d = toreal(d.parentTrueType), detail_parentUser_s = tostring(d.parentUser), detail_parentUserDomain_s = tostring(d.parentUserDomain), detail_plang_d = toreal(d.plang), detail_processCmd_s = tostring(d.processCmd), detail_processFileCreation_d = toreal(d.processFileCreation), detail_processFileHashSha1_s = tostring(d.processFileHashSha1), detail_processFileHashSha256_s = tostring(d.processFileHashSha256), detail_processFileModifiedTime_d = toreal(d.processFileModifiedTime), detail_processFilePath_s = tostring(d.processFilePath), detail_processFileSize_d = toreal(d.processFileSize), detail_processLaunchTime_d = toreal(d.processLaunchTime), detail_processPid_d = toreal(d.processPid), detail_processSigner_s = tostring(d.processSigner), detail_processSignerValid_s = tostring(d.processSignerValid), detail_processTrueType_d = toreal(d.processTrueType), detail_processUser_s = tostring(d.processUser), detail_processUserDomain_s = tostring(d.processUserDomain), detail_timezone_s = tostring(d.timezone), detail_userDomain_s = tostring(d.userDomain), detail_objectAppName_s = tostring(d.objectAppName), detail_objectContentName_s = tostring(d.objectContentName), detail_objectFirstSeen_d = toreal(d.objectFirstSeen), detail_objectLastSeen_d = toreal(d.objectLastSeen), detail_objectRawDataStr_s = tostring(d.objectRawDataStr), detail_parentSigner_s = tostring(d.parentSigner), detail_parentSignerValid_s = tostring(d.parentSignerValid), detail_objectSubTrueType_d = toreal(d.objectSubTrueType), detail_hostName_s = tostring(d.hostName), detail_objectIps_s = tostring(d.objectIps), detail_srcFirstSeen_d = toreal(d.srcFirstSeen), detail_srcLastSeen_d = toreal(d.srcLastSeen), detail_actResult_s = tostring(d.actResult), detail_channel_s = tostring(d.channel), detail_domainName_s = tostring(d.domainName), detail_endpointMacAddress_s = tostring(d.endpointMacAddress), detail_eventSubName_s = tostring(d.eventSubName), detail_firstAct_s = tostring(d.firstAct), detail_firstActResult_s = tostring(d.firstActResult), detail_mDevice_s = tostring(d.mDevice), detail_malDst_s = tostring(d.malDst), detail_malName_s = tostring(d.malName), detail_malSubType_s = tostring(d.malSubType), detail_objectFileHashSha1_s = tostring(d.objectFileHashSha1), detail_objectFileName_s = tostring(d.objectFileName), detail_objectFilePath_s = tostring(d.objectFilePath), detail_objectType_s = tostring(d.objectType), detail_scanType_s = tostring(d.scanType), detail_secondAct_s = tostring(d.secondAct), detail_secondActResult_s = tostring(d.secondActResult), detail_act_s = tostring(d.act), detail_aggregatedCount_d = toreal(d.aggregatedCount), detail_app_s = tostring(d.app), detail_appGroup_s = tostring(d.appGroup), detail_aptRelated_s = tostring(d.aptRelated), detail_clientFlag_s = tostring(d.clientFlag), detail_detectionType_s = tostring(d.detectionType), detail_deviceDirection_s = tostring(d.deviceDirection), detail_deviceGUID_g = tostring(d.deviceGUID), detail_deviceMacAddress_s = tostring(d.deviceMacAddress), detail_dhost_s = tostring(d.dhost), detail_dmac_s = tostring(d.dmac), detail_dpt_d = toreal(d.dpt), detail_dst_s = tostring(d.dst), detail_dstGroup_s = tostring(d.dstGroup), detail_dstZone_s = tostring(d.dstZone), detail_dvchost_s = tostring(d.dvchost), detail_eventId_d = toreal(d.eventId), detail_eventName_s = tostring(d.eventName), detail_eventSourceType_s = tostring(d.eventSourceType), detail_eventTime_d = toreal(d.eventTime), detail_fileExt_s = tostring(d.fileExt), detail_fileHash_s = tostring(d.fileHash), detail_fileName_s = tostring(d.fileName), detail_filePath_s = tostring(d.filePath), detail_filePathName_s = tostring(d.filePathName), detail_fileSize_d = toreal(d.fileSize), detail_filterRiskLevel_s = tostring(d.filterRiskLevel), detail_fullPath_s = tostring(d.fullPath), detail_hostSeverity_d = toreal(d.hostSeverity), detail_interestedGroup_s = tostring(d.interestedGroup), detail_interestedHost_s = tostring(d.interestedHost), detail_interestedIp_s = tostring(d.interestedIp), detail_malType_s = tostring(d.malType), detail_malTypeGroup_s = tostring(d.malTypeGroup), detail_pAttackPhase_s = tostring(d.pAttackPhase), detail_pComp_s = tostring(d.pComp), detail_peerGroup_s = tostring(d.peerGroup), detail_peerHost_s = tostring(d.peerHost), detail_peerIp_s = tostring(d.peerIp), detail_pname_s = tostring(d.pname), detail_remarks_s = tostring(d.remarks), detail_rt_t = todatetime(datetime(1970-01-01) + tolong(d.rt) * 1ms), detail_rtHour_d = toreal(d.rtHour), detail_ruleId_d = toreal(d.ruleId), detail_ruleName_s = tostring(d.ruleName), detail_senderIp_s = tostring(d.senderIp), detail_severity_d = toreal(d.severity), detail_shost_s = tostring(d.shost), detail_smac_s = tostring(d.smac), detail_spt_d = toreal(d.spt), detail_src_s = tostring(d.src), detail_srcGroup_s = tostring(d.srcGroup), detail_srcZone_s = tostring(d.srcZone), detail_tags_s = tostring(d.tags), detail_threatType_s = tostring(d.threatType), detail_uuid_g = tostring(d.uuid), detail_cat_d = toreal(d.cat), detail_endpointGUID_g = tostring(d.endpointGUID), detail_endpointHostName_s = tostring(d.endpointHostName), detail_endpointIp_s = tostring(d.endpointIp), detail_processName_s = tostring(d.processName), detail_proto_s = tostring(d.proto)", + "outputStream": "Custom-TrendMicro_XDR_OAT_V2_CL" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName'))]" + ], + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "[variables('connectorId')]", + "title": "Trend Micro Vision One - OAT", + "publisher": "Trend Micro", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "**V1-compatible** CCF connector for Observed Attack Techniques. Column names exactly match the legacy V1 Azure Function connector (detail_*_s prefix, endpoint_ips_s/endpoint_name_s/endpoint_guid_g object expansion, xdrCustomerId_g lowercase). Full payload also preserved as `RawData` for fallback parsing.", + "graphQueriesTableName": "TrendMicro_XDR_OAT_V2_CL", + "dataTypes": [ + { + "name": "TrendMicro_XDR_OAT_V2_CL", + "lastDataReceivedQuery": "TrendMicro_XDR_OAT_V2_CL | summarize Time = max(TimeGenerated) | where isnotempty(Time)" + } + ], + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "TrendMicro_XDR_OAT_V2_CL", + "baseQuery": "TrendMicro_XDR_OAT_V2_CL" + } + ], + "sampleQueries": [ + { + "description": "All OAT Detections", + "query": "TrendMicro_XDR_OAT_V2_CL | sort by TimeGenerated desc | take 10" + }, + { + "description": "High Risk Credential Dumping (V1-compatible)", + "query": "TrendMicro_XDR_OAT_V2_CL | where detail_filterRiskLevel_s == 'high' | project TimeGenerated, detail_endpointHostName_s, detail_processCmd_s, detail_objectCmd_s, detail_processFileHashSha256_s" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions required", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ] + }, + "instructionSteps": [ + { + "title": "1. Get API Token", + "description": "Obtain your Trend Micro Vision One API token from the Administration Console", + "instructions": [ + { + "type": "InfoMessage", + "parameters": { + "text": "Log in to Trend Micro Vision One Console → Administration → API Keys → Generate new API key with 'SIEM' role permissions" + } + } + ] + }, + { + "title": "2. Connect via Azure Portal", + "description": "Deploy the connection using the button below", + "instructions": [ + { + "type": "InstallAgent", + "parameters": {} + } + ] + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'), '-connection')]", + "location": "[parameters('workspace-location')]", + "condition": "[not(empty(parameters('apikey')))]", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions', parameters('workspace'), 'Microsoft.SecurityInsights', variables('connectorId'))]" + ], + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[variables('connectorId')]", + "dataType": "TrendMicro_XDR_OAT_V2_CL", + "dcrConfig": { + "streamName": "Custom-TrendMicro_XDR_OAT_V2_CL", + "dataCollectionEndpoint": "[reference(resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName')), '2021-09-01-preview').logsIngestion.endpoint]", + "dataCollectionRuleImmutableId": "[reference(resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName')), '2021-09-01-preview').immutableId]" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[concat('https://', variables('apiHostnames')[parameters('trendaiRegion')], '/v3.0/oat/detections')]", + "rateLimitQPS": 10, + "queryWindowInMin": 5, + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-dd'T'HH:mm:ss'Z'", + "startTimeAttributeName": "detectedStartDateTime", + "endTimeAttributeName": "detectedEndDateTime", + "queryParameters": { + "top": "500" + }, + "headers": "[if(empty(parameters('oatFilter')), json('{}'), json(concat('{\"TMV1-Filter\": \"', parameters('oatFilter'), '\"}')))]", + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.items" + ], + "format": "json" + }, + "paging": { + "pagingType": "LinkHeader", + "linkHeaderTokenJsonPath": "$.nextLink" + } + } + } + ] +} diff --git a/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-newSchema.json b/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-newSchema.json new file mode 100644 index 00000000000..325eea0efe7 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/arm-template-oat-newSchema.json @@ -0,0 +1,534 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass the arm-ttk test, 'Location-Should-Not-Be-Hardcoded'. Instead the `workspace-location` derived from the log analytics workspace is used." + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Azure region where your Log Analytics workspace is located (e.g., centralus, eastus, westeurope)" + } + }, + "subscription": { + "defaultValue": "[last(split(subscription().id, '/'))]", + "type": "string", + "metadata": { + "description": "subscription id where Microsoft Sentinel is configured" + } + }, + "resourceGroupName": { + "defaultValue": "[resourceGroup().name]", + "type": "string", + "metadata": { + "description": "Resource group name where Microsoft Sentinel is configured" + } + }, + "workspace": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace where Microsoft Sentinel is enabled" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "UK", + "allowedValues": [ + "UK", + "US", + "SG", + "CA", + "JP" + ], + "metadata": { + "description": "TrendAI API region where your account is hosted" + } + }, + "oatFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter for OAT API. Example: (riskLevel eq 'high'). Leave empty for no filter." + } + } + }, + "variables": { + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "_solutionName": "TrendAI-OAT", + "_solutionVersion": "3.0.1", + "_solutionAuthor": "TrendAI", + "_packageIcon": "", + "_solutionId": "azuresentinel.azure-sentinel-solution-azuresentinel.azure-sentinel-TrendAI-OAT", + "dataConnectorVersionConnectorDefinition": "1.0.0", + "dataConnectorVersionConnections": "1.0.0", + "_solutionTier": "Community", + "_dataConnectorContentIdConnectorDefinition": "TrendAIOATConnectorDefinition", + "dataConnectorTemplateNameConnectorDefinition": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition')))]", + "_dataConnectorContentIdConnections": "TrendAIOATConnections", + "dataConnectorTemplateNameConnections": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections')))]", + "_logAnalyticsTableId1": "OAT_CL", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + }, + "selectedApiHostname": "[variables('apiHostnames')[parameters('trendaiRegion')]]", + "dceResourceId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/TrendAI-OAT-DCE')]", + "dcrResourceId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionRules/TrendAI-OAT-DCR')]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]", + "location": "[parameters('workspace-location')]", + "apiVersion": "2023-04-01-preview", + "properties": { + "version": "[variables('_solutionVersion')]", + "kind": "Solution", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_solutionId')]", + "source": { + "kind": "Solution", + "name": "[variables('_solutionName')]", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "DataConnector", + "contentId": "[variables('dataConnectorVersionConnectorDefinition')]", + "version": "[variables('_dataConnectorContentIdConnectorDefinition')]" + } + ] + }, + "firstPublishDate": "2024-01-15", + "providers": [ + "[variables('_solutionAuthor')]" + ], + "contentKind": "Solution", + "packageId": "[variables('_solutionId')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]", + "displayName": "[variables('_solutionName')]", + "publisherDisplayName": "[variables('_solutionId')]", + "descriptionHtml": "TrendAI OAT (Observed Attack Techniques) data connector for Microsoft Sentinel", + "icon": "[variables('_packageIcon')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnectorDefinition'))]", + "contentKind": "DataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnectorDefinition')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "TrendAI-OAT-DCE", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionEndpoints", + "location": "[parameters('workspace-location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + }, + { + "name": "TrendAI-OAT-DCR", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[parameters('workspace-location')]", + "kind": null, + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', 'TrendAI-OAT-DCE')]", + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('_logAnalyticsTableId1'))]" + ], + "properties": + { + "dataCollectionEndpointId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/TrendAI-OAT-DCE')]", + "streamDeclarations": { + "Custom-OAT_CL": { + "columns": [ + {"name": "source", "type": "string"}, + {"name": "uuid", "type": "string"}, + {"name": "detectedDateTime", "type": "datetime"}, + {"name": "filters", "type": "dynamic"}, + {"name": "detail", "type": "dynamic"}, + {"name": "ingestedDateTime", "type": "datetime"}, + {"name": "entityType", "type": "string"}, + {"name": "entityName", "type": "string"}, + {"name": "endpoint", "type": "dynamic"} + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "oatDestination" + } + ] + }, + "dataFlows": [ + { + "streams": ["Custom-OAT_CL"], + "destinations": ["oatDestination"], + "transformKql": "source | extend TimeGenerated = detectedDateTime, endpointHostName = tostring(detail.endpointHostName), endpointIp = detail.endpointIp, filterRiskLevel = tostring(detail.filterRiskLevel), mitreTacticIds = filters[0].mitreTacticIds, mitreTechniqueIds = filters[0].mitreTechniqueIds, endpointGuid = tostring(endpoint.agentGuid), endpointIps = endpoint.ips | project-away detectedDateTime", + "outputStream": "Custom-OAT_CL" + } + ] + } + }, + { + "name": "[variables('_logAnalyticsTableId1')]", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": + { + "totalRetentionInDays": 30, + "plan": "Analytics", + "retentionInDays": 30, + "schema": { + "name": "[variables('_logAnalyticsTableId1')]", + "tableSubType": "DataCollectionRuleBased", + "tableType": "CustomLog", + "columns": [ + {"name": "source", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "uuid", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "filters", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "detail", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "ingestedDateTime", "type": "datetime", "isDefaultDisplay": false, "isHidden": false}, + {"name": "entityType", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "entityName", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "endpoint", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "endpointHostName", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "endpointIp", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "filterRiskLevel", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "mitreTacticIds", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "mitreTechniqueIds", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "endpointGuid", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "endpointIps", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "TimeGenerated", "type": "datetime", "isDefaultDisplay": false, "isHidden": false} + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition'),'-', variables('dataConnectorVersionConnectorDefinition'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": + { + "connectorUiConfig": { + "id": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "title": "TrendAI OAT Detections", + "publisher": "TrendAI", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "The TrendAI OAT connector allows you to ingest Observed Attack Techniques detections from TrendAI into Microsoft Sentinel.", + "graphQueriesTableName": "[variables('_logAnalyticsTableId1')]", + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "OAT_CL", + "baseQuery": "[variables('_logAnalyticsTableId1')]" + } + ], + "sampleQueries": [ + { + "description": "All OAT Detections", + "query": "[concat(variables('_logAnalyticsTableId1'), '\n| sort by TimeGenerated desc')]" + } + ], + "dataTypes": [ + { + "name": "[variables('_logAnalyticsTableId1')]", + "lastDataReceivedQuery": "[concat(variables('_logAnalyticsTableId1'), '\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)')]" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "TrendAI API Key", + "description": "A TrendAI API key is required to connect to the TrendAI OAT API." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect TrendAI OAT to Microsoft Sentinel", + "description": "Provide your TrendAI API credentials to establish the connection. Note: Filter is configured during ARM template deployment.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "placeholder": "Enter your TrendAI API Key", + "type": "text", + "name": "apikey" + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectButtonLabel": "Connect", + "disconnectButtonLabel": "Disconnect" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections'), variables('dataConnectorVersionConnections'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]", + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('workspace'), '/providers/Microsoft.SecurityInsights/contentTemplates/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnections'))]", + "contentKind": "ResourcesDataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnections')]", + "parameters": + { + "connectorDefinitionName": { + "defaultValue": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "type": "string", + "minLength": 1 + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "string" + }, + "dcrConfig": { + "type": "object" + }, + "apikey": { + "defaultValue": "", + "type": "securestring" + }, + "tmv1filter": { + "defaultValue": "[parameters('oatFilter')]", + "type": "string" + }, + "selectedApiHostname": { + "defaultValue": "[variables('selectedApiHostname')]", + "type": "string" + } + }, + "variables": { + "_dataConnectorContentIdConnections": "[variables('_dataConnectorContentIdConnections')]" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections'))]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorVersionConnections')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'TrendAI-OAT')]", + "apiVersion": "2022-12-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": + { + "connectorDefinitionName": "[[parameters('connectorDefinitionName')]", + "dataType": "TrendAI OAT Detections", + "dcrConfig": { + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]", + "streamName": "Custom-OAT_CL" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[[concat('https://', parameters('selectedApiHostname'), '/v3.0/oat/detections')]", + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-dd'T'HH:mm:ss'Z'", + "startTimeAttributeName": "detectedStartDateTime", + "endTimeAttributeName": "detectedEndDateTime", + "queryWindowInMin": 5, + "queryParameters": { + "top": "500" + }, + "headers": "[[if(empty(parameters('tmv1filter')), json('{}'), json(concat('{\"TMV1-Filter\": \"', parameters('tmv1filter'), '\"}')))]", + "rateLimitQPS": 10, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.items" + ], + "format": "json" + }, + "isActive": true + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections'),'-', variables('dataConnectorVersionConnections'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + } + ] +} diff --git a/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-compatibleSchema.json b/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-compatibleSchema.json new file mode 100644 index 00000000000..0fb8f7fe2fe --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-compatibleSchema.json @@ -0,0 +1,436 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "3.0.0.0", + "metadata": { + "description": "Microsoft-recommended pattern: DCR transforms scalar fields, arrays stored as dynamic, expanded by post-ingestion parsers" + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": {"description": "Log Analytics workspace name"} + }, + "workspace-location": { + "type": "string", + "metadata": {"description": "Workspace Azure region"} + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "US", + "allowedValues": ["UK", "US", "SG", "CA", "JP"], + "metadata": {"description": "Trend Vision One region"} + }, + "apikey": { + "type": "securestring", + "defaultValue": "", + "metadata": {"description": "Trend AI Vision One API Key (Bearer token without 'Bearer' prefix)"} + }, + "tmv1Filter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Filter expression to limit which alerts are ingested. Examples: investigationStatus eq 'New' and contains(impactScopeEntityValue,'nimda'). Leave empty to fetch all alerts." + } + } + }, + "variables": { + "tableName": "TrendMicro_XDR_WORKBENCH_V2_CL", + "dceName": "TrendMicro-XDR-DCE", + "dcrName": "TrendMicro-XDR-Workbench-DCR", + "connectorId": "TrendMicro_XDR_Workbench", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + }, + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[concat(parameters('workspace'), '/', variables('tableName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "schema": { + "name": "[variables('tableName')]", + "columns": [ + {"name": "TimeGenerated", "type": "datetime"}, + {"name": "SourceSystem", "type": "string"}, + {"name": "MG", "type": "string"}, + {"name": "ManagementGroupName", "type": "string"}, + {"name": "Computer", "type": "string"}, + {"name": "RawData", "type": "string"}, + {"name": "workbenchId_s", "type": "string"}, + {"name": "schemaVersion_s", "type": "string"}, + {"name": "investigationStatus_s", "type": "string"}, + {"name": "alertStatus_s", "type": "string"}, + {"name": "investigationResult_s", "type": "string"}, + {"name": "workbenchLink_s", "type": "string"}, + {"name": "alertProvider_s", "type": "string"}, + {"name": "modelId_g", "type": "string"}, + {"name": "modelId_s", "type": "string"}, + {"name": "model_s", "type": "string"}, + {"name": "workbenchName_s", "type": "string"}, + {"name": "modelType_s", "type": "string"}, + {"name": "priorityScore_d", "type": "real"}, + {"name": "severity_s", "type": "string"}, + {"name": "createdTime_t", "type": "datetime"}, + {"name": "updatedTime_t", "type": "datetime"}, + {"name": "alertTriggerTimestamp_t", "type": "datetime"}, + {"name": "workbenchCompleteTimestamp_t", "type": "datetime"}, + {"name": "incidentId_s", "type": "string"}, + {"name": "description_s", "type": "string"}, + {"name": "desktopCount_d", "type": "real"}, + {"name": "serverCount_d", "type": "real"}, + {"name": "accountCount_d", "type": "real"}, + {"name": "emailAddressCount_d", "type": "real"}, + {"name": "containerCount_d", "type": "real"}, + {"name": "cloudIdentityCount_d", "type": "real"}, + {"name": "cloudWorkloadCount_d", "type": "real"}, + {"name": "indicators_s", "type": "string"}, + {"name": "indicators", "type": "dynamic"}, + {"name": "impactScope_s", "type": "string"}, + {"name": "impactScope_Summary_s", "type": "string"}, + {"name": "entities", "type": "dynamic"}, + {"name": "matchedRules_s", "type": "string"}, + {"name": "matchedRules", "type": "dynamic"}, + {"name": "xdrCustomerID_g", "type": "string"}, + {"name": "FileName_s", "type": "string"}, + {"name": "FileHashValue_s", "type": "string"}, + {"name": "DomainName_s", "type": "string"}, + {"name": "FileDirectory_s", "type": "string"}, + {"name": "IPAddress", "type": "string"}, + {"name": "URL_s", "type": "string"}, + {"name": "HostHostName_s", "type": "string"}, + {"name": "ProcessCommandLine_s", "type": "string"}, + {"name": "RegistryKey_s", "type": "string"}, + {"name": "RegistryValue_s", "type": "string"}, + {"name": "RegistryValueName_s", "type": "string"}, + {"name": "UserAccountNTDomain_s", "type": "string"}, + {"name": "UserAccountName_s", "type": "string"}, + {"name": "MailboxPrimaryAddress_s", "type": "string"}, + {"name": "MalwareName_s", "type": "string"} + ] + } + } + }, + { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dceName')]", + "location": "[parameters('workspace-location')]", + "properties": { + "networkAcls": {"publicNetworkAccess": "Enabled"} + } + }, + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dcrName')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]", + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]" + ], + "properties": { + "dataCollectionEndpointId": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]", + "streamDeclarations": { + "Custom-TrendMicro_XDR_WORKBENCH_V2_CL": { + "columns": [ + {"name": "id", "type": "string"}, + {"name": "schemaVersion", "type": "string"}, + {"name": "investigationStatus", "type": "string"}, + {"name": "status", "type": "string"}, + {"name": "investigationResult", "type": "string"}, + {"name": "workbenchLink", "type": "string"}, + {"name": "alertProvider", "type": "string"}, + {"name": "modelId", "type": "string"}, + {"name": "model", "type": "string"}, + {"name": "modelType", "type": "string"}, + {"name": "score", "type": "int"}, + {"name": "severity", "type": "string"}, + {"name": "createdDateTime", "type": "datetime"}, + {"name": "updatedDateTime", "type": "datetime"}, + {"name": "incidentId", "type": "string"}, + {"name": "description", "type": "string"}, + {"name": "impactScope", "type": "dynamic"}, + {"name": "indicators", "type": "dynamic"}, + {"name": "matchedRules", "type": "dynamic"} + ] + } + }, + "destinations": { + "logAnalytics": [{ + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + }] + }, + "dataFlows": [{ + "streams": ["Custom-TrendMicro_XDR_WORKBENCH_V2_CL"], + "destinations": ["clv2ws1"], + "transformKql": "source | extend TimeGenerated = todatetime(createdDateTime) | extend SourceSystem = 'RestAPI' | extend Computer = '' | extend MG = '' | extend ManagementGroupName = '' | extend RawData = tostring(indicators) | extend workbenchId_s = tostring(id) | extend schemaVersion_s = tostring(schemaVersion) | extend investigationStatus_s = tostring(investigationStatus) | extend alertStatus_s = tostring(status) | extend investigationResult_s = tostring(investigationResult) | extend workbenchLink_s = tostring(workbenchLink) | extend alertProvider_s = tostring(alertProvider) | extend modelId_g = tostring(modelId) | extend modelId_s = tostring(modelId) | extend model_s = tostring(model) | extend workbenchName_s = tostring(model) | extend modelType_s = tostring(modelType) | extend priorityScore_d = todouble(score) | extend severity_s = tostring(severity) | extend createdTime_t = todatetime(createdDateTime) | extend updatedTime_t = todatetime(updatedDateTime) | extend alertTriggerTimestamp_t = todatetime(createdDateTime) | extend workbenchCompleteTimestamp_t = todatetime(updatedDateTime) | extend incidentId_s = tostring(incidentId) | extend description_s = tostring(description) | extend desktopCount_d = todouble(impactScope.desktopCount) | extend serverCount_d = todouble(impactScope.serverCount) | extend accountCount_d = todouble(impactScope.accountCount) | extend emailAddressCount_d = todouble(impactScope.emailAddressCount) | extend containerCount_d = todouble(impactScope.containerCount) | extend cloudIdentityCount_d = todouble(impactScope.cloudIdentityCount) | extend cloudWorkloadCount_d = todouble(impactScope.cloudWorkloadCount) | extend indicators_dynamic = indicators | extend indicators_s = tostring(indicators) | extend impactScope_s = tostring(impactScope) | extend impactScope_Summary_s = tostring(impactScope) | extend entities = impactScope.entities | extend matchedRules_dynamic = matchedRules | extend matchedRules_s = tostring(matchedRules) | extend xdrCustomerID_g = '' | extend FileName_s = '' | extend FileHashValue_s = '' | extend DomainName_s = '' | extend FileDirectory_s = '' | extend IPAddress = '' | extend URL_s = '' | extend HostHostName_s = '' | extend ProcessCommandLine_s = '' | extend RegistryKey_s = '' | extend RegistryValue_s = '' | extend RegistryValueName_s = '' | extend UserAccountNTDomain_s = '' | extend UserAccountName_s = '' | extend MailboxPrimaryAddress_s = '' | extend MalwareName_s = '' | extend indicators = indicators_dynamic | extend matchedRules = matchedRules_dynamic | project-away id, schemaVersion, investigationStatus, status, investigationResult, workbenchLink, alertProvider, modelId, model, modelType, score, severity, createdDateTime, updatedDateTime, incidentId, description, impactScope, indicators_dynamic, matchedRules_dynamic", + "outputStream": "Custom-TrendMicro_XDR_WORKBENCH_V2_CL" + }] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName'))]" + ], + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "[variables('connectorId')]", + "title": "TrendAI Vision One - Workbench Data Connector", + "publisher": "Trend AI", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "**Microsoft-recommended architecture**: DCR transforms scalar fields, arrays stored as dynamic columns. Post-deployment: create 3 saved KQL functions for IOC/entity extraction. Fully backward-compatible schema.", + "graphQueriesTableName": "TrendMicro_XDR_WORKBENCH_V2_CL", + "dataTypes": [{ + "name": "TrendMicro_XDR_WORKBENCH_V2_CL", + "lastDataReceivedQuery": "TrendMicro_XDR_WORKBENCH_V2_CL | summarize Time = max(TimeGenerated) | where isnotempty(Time)" + }], + "graphQueries": [{ + "metricName": "Total data received", + "legend": "TrendMicro_XDR_WORKBENCH_V2_CL", + "baseQuery": "TrendMicro_XDR_WORKBENCH_V2_CL" + }], + "sampleQueries": [ + { + "description": "All Workbench Alerts (Raw Table)", + "query": "TrendMicro_XDR_WORKBENCH_V2_CL | take 10" + }, + { + "description": "High/Critical Severity Alerts", + "query": "TrendMicro_XDR_WORKBENCH_V2_CL | where severity_s in ('high', 'critical') | project TimeGenerated, workbenchId_s, workbenchName_s, severity_s, priorityScore_d" + } + ], + "connectivityCriteria": [{ + "type": "HasDataConnectors" + }], + "availability": {"status": 1, "isPreview": false}, + "permissions": { + "resourceProvider": [{ + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions required", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": {"write": true, "read": true, "delete": true} + }] + }, + "instructionSteps": [ + { + "title": "1. Get API Token", + "description": "Obtain your Trend AI Vision One API token from the Administration Console", + "instructions": [ + { + "type": "InfoMessage", + "parameters": { + "text": "Log in to Trend AI Vision One Console → Administration → API Keys → Generate new API key with 'SIEM' role permissions" + } + } + ] + }, + { + "title": "2. Deploy Connector", + "description": "Click Deploy below", + "instructions": [ + { + "type": "InstallAgent", + "parameters": {} + } + ] + }, + { + "title": "3. Post-Deployment: Create Saved Functions", + "description": "After deployment, create 3 saved KQL functions in Log Analytics for IOC/entity extraction. See deployment guide for function definitions.", + "instructions": [ + { + "type": "InfoMessage", + "parameters": { + "text": "Run the 3 KQL function creation scripts from the deployment package to enable IOC extraction from indicators/entities dynamic columns" + } + } + ] + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'), '-connection')]", + "location": "[parameters('workspace-location')]", + "condition": "[not(empty(parameters('apikey')))]", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions', parameters('workspace'), 'Microsoft.SecurityInsights', variables('connectorId'))]" + ], + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[variables('connectorId')]", + "dataType": "TrendMicro_XDR_WORKBENCH_V2_CL", + "dcrConfig": { + "streamName": "Custom-TrendMicro_XDR_WORKBENCH_V2_CL", + "dataCollectionEndpoint": "[reference(resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName')), '2021-09-01-preview').logsIngestion.endpoint]", + "dataCollectionRuleImmutableId": "[reference(resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName')), '2021-09-01-preview').immutableId]" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[concat('https://', variables('apiHostnames')[parameters('trendaiRegion')], '/v3.0/workbench/alerts')]", + "rateLimitQPS": 1, + "queryWindowInMin": 5, + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "startDateTime", + "endTimeAttributeName": "endDateTime", + "headers": { + "TMV1-Filter": "[parameters('tmv1Filter')]" + } + }, + "response": { + "eventsJsonPaths": ["$.items"], + "format": "json" + }, + "paging": { + "pagingType": "LinkHeader", + "linkHeaderTokenJsonPath": "$.nextLink" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', guid('workbench-analytic-rule', parameters('workspace')))]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]" + ], + "properties": { + "description": "This Query creates an incident based on Trend Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.", + "displayName": "Trend Vision One - Create Incident for Workbench Alerts", + "enabled": false, + "query": "TrendMicroWorkbench_Complete\n| extend Severity = case(severity_s == \"low\", \"Informational\",\n severity_s == \"medium\", \"Low\",\n severity_s == \"high\", \"Medium\",\n \"High\"\n )", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "tactics": [], + "techniques": [], + "entityMappings": [ + { + "fieldMappings": [ + {"columnName": "UserAccountName_s", "identifier": "Name"}, + {"columnName": "UserAccountNTDomain_s", "identifier": "NTDomain"} + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + {"columnName": "FileName_s", "identifier": "Name"}, + {"columnName": "FileDirectory_s", "identifier": "Directory"} + ], + "entityType": "File" + }, + { + "fieldMappings": [ + {"columnName": "ProcessCommandLine_s", "identifier": "CommandLine"} + ], + "entityType": "Process" + }, + { + "fieldMappings": [ + {"columnName": "RegistryKey_s", "identifier": "Key"} + ], + "entityType": "RegistryKey" + }, + { + "fieldMappings": [ + {"columnName": "RegistryValueName_s", "identifier": "Name"}, + {"columnName": "RegistryValue_s", "identifier": "Value"} + ], + "entityType": "RegistryValue" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + }, + "customDetails": { + "Provider": "alertProvider_s", + "PriorityScore": "priorityScore_d", + "ImpactScopeSummary": "impactScope_Summary_s", + "WorkbenchID": "workbenchId_s", + "WorkbenchLink": "workbenchLink_s", + "WorkbenchName": "workbenchName_s", + "Severity": "severity_s", + "XDRCustomerID": "xdrCustomerID_g", + "CreatedAt": "createdTime_t" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "{{workbenchName_s}}", + "alertSeverityColumnName": "Severity", + "alertDescriptionFormat": "{{description_s}}" + }, + "incidentConfiguration": { + "createIncident": true, + "groupingConfiguration": { + "matchingMethod": "Selected", + "enabled": true, + "lookbackDuration": "PT5M", + "reopenClosedIncident": false, + "groupByCustomDetails": ["WorkbenchID"] + } + } + } + }, + { + "type": "Microsoft.Insights/workbooks", + "name": "[guid('workbench-workbook', parameters('workspace'))]", + "location": "[parameters('workspace-location')]", + "apiVersion": "2023-06-01", + "kind": "shared", + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]" + ], + "properties": { + "displayName": "TrendVisionOneWorkbenchOverview", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Trend Vision One - Workbench Alerts\\n---\\n[Trend Micro Success Portal](https://success.trendmicro.com)\\n\\nIf you have any feedback, please send to \"},\"name\":\"text - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(7d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 7 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 30 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), model_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Detection Models in Last 30 Days\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by severity_s\\n| render piechart\",\"size\":0,\"title\":\"Alerts by Severity\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 4\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| where isnotempty(HostHostName_s) and HostHostName_s != '[]'\\n| summarize Alerts = count() by HostHostName_s\\n| top 10 by Alerts desc\",\"size\":0,\"title\":\"Top 10 Affected Hosts\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 5\"}],\"styleSettings\":{},\"fromTemplateId\":\"sentinel-TrendVisionOneWorkbench\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}", + "version": "1.0", + "sourceId": "[variables('workspaceResourceId')]", + "category": "sentinel" + } + } + ], + "outputs": { + "tableName": { + "type": "string", + "value": "[variables('tableName')]" + }, + "analyticRuleId": { + "type": "string", + "value": "[guid('workbench-analytic-rule', parameters('workspace'))]" + }, + "workbookId": { + "type": "string", + "value": "[guid('workbench-workbook', parameters('workspace'))]" + }, + "message": { + "type": "string", + "value": "✅ Deployment complete! Deployed: Table, DCE, DCR, Data connector, Analytic rule (disabled), and Workbook. Next steps: 1) Deploy parser: Use templates/legacy/deploy-parser-function.json 2) Enable analytic rule: Sentinel → Analytics 3) View dashboard: Sentinel → Workbooks" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-newSchema.json b/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-newSchema.json new file mode 100644 index 00000000000..67076dc83ef --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/arm-template-workbench-newSchema.json @@ -0,0 +1,546 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass the arm-ttk test, 'Location-Should-Not-Be-Hardcoded'. Instead the `workspace-location` derived from the log analytics workspace is used." + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Azure region where your Log Analytics workspace is located (e.g., centralus, eastus, westeurope)" + } + }, + "subscription": { + "defaultValue": "[last(split(subscription().id, '/'))]", + "type": "string", + "metadata": { + "description": "subscription id where Microsoft Sentinel is configured" + } + }, + "resourceGroupName": { + "defaultValue": "[resourceGroup().name]", + "type": "string", + "metadata": { + "description": "Resource group name where Microsoft Sentinel is configured" + } + }, + "workspace": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace where Microsoft Sentinel is enabled" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "UK", + "allowedValues": [ + "UK", + "US", + "SG", + "CA", + "JP" + ], + "metadata": { + "description": "TrendAI API region where your account is hosted" + } + }, + "workbenchFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter for Workbench API. Example: (investigationStatus eq 'New'). Leave empty for no filter." + } + } + }, + "variables": { + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "_solutionName": "TrendAI", + "_solutionVersion": "3.0.1", + "_solutionAuthor": "TrendAI", + "_packageIcon": "", + "_solutionId": "azuresentinel.azure-sentinel-solution-azuresentinel.azure-sentinel-TrendAI", + "dataConnectorVersionConnectorDefinition": "1.0.0", + "dataConnectorVersionConnections": "1.0.0", + "_solutionTier": "Community", + "_dataConnectorContentIdConnectorDefinition": "TrendAIWorkbenchConnectorDefinition", + "dataConnectorTemplateNameConnectorDefinition": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition')))]", + "_dataConnectorContentIdConnections": "TrendAIWorkbenchConnections", + "dataConnectorTemplateNameConnections": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections')))]", + "_logAnalyticsTableId1": "WorkbenchAlert_CL", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + }, + "selectedApiHostname": "[variables('apiHostnames')[parameters('trendaiRegion')]]", + "dceResourceId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/TrendAI-DataConnector-DCE')]", + "dcrResourceId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionRules/TrendAI-DataConnector-DCR')]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]", + "location": "[parameters('workspace-location')]", + "apiVersion": "2023-04-01-preview", + "properties": { + "version": "[variables('_solutionVersion')]", + "kind": "Solution", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_solutionId')]", + "source": { + "kind": "Solution", + "name": "[variables('_solutionName')]", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "DataConnector", + "contentId": "[variables('dataConnectorVersionConnectorDefinition')]", + "version": "[variables('_dataConnectorContentIdConnectorDefinition')]" + } + ] + }, + "firstPublishDate": "2023-12-05", + "providers": [ + "[variables('_solutionAuthor')]" + ], + "contentKind": "Solution", + "packageId": "[variables('_solutionId')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]", + "displayName": "[variables('_solutionName')]", + "publisherDisplayName": "[variables('_solutionId')]", + "descriptionHtml": "test", + "icon": "[variables('_packageIcon')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnectorDefinition'))]", + "contentKind": "DataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnectorDefinition')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "TrendAI-DataConnector-DCE", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionEndpoints", + "location": "[parameters('workspace-location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + }, + { + "name": "TrendAI-DataConnector-DCR", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[parameters('workspace-location')]", + "kind": null, + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', 'TrendAI-DataConnector-DCE')]", + "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('_logAnalyticsTableId1'))]" + ], + "properties": + { + "dataCollectionEndpointId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/TrendAI-DataConnector-DCE')]", + "streamDeclarations": { + "Custom-WorkbenchAlert_CL": { + "columns": [ + {"name": "schemaVersion", "type": "string"}, + {"name": "id", "type": "string"}, + {"name": "investigationStatus", "type": "string"}, + {"name": "status", "type": "string"}, + {"name": "investigationResult", "type": "string"}, + {"name": "workbenchLink", "type": "string"}, + {"name": "alertProvider", "type": "string"}, + {"name": "modelId", "type": "string"}, + {"name": "model", "type": "string"}, + {"name": "modelType", "type": "string"}, + {"name": "score", "type": "int"}, + {"name": "severity", "type": "string"}, + {"name": "createdDateTime", "type": "datetime"}, + {"name": "updatedDateTime", "type": "datetime"}, + {"name": "ownerIds", "type": "dynamic"}, + {"name": "incidentId", "type": "string"}, + {"name": "impactScope", "type": "dynamic"}, + {"name": "description", "type": "string"}, + {"name": "matchedRules", "type": "dynamic"}, + {"name": "indicators", "type": "dynamic"} + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "workbenchDestination" + } + ] + }, + "dataFlows": [ + { + "streams": ["Custom-WorkbenchAlert_CL"], + "destinations": ["workbenchDestination"], + "transformKql": "source | extend TimeGenerated = createdDateTime | project-away createdDateTime", + "outputStream": "Custom-WorkbenchAlert_CL" + } + ] + } + }, + { + "name": "[variables('_logAnalyticsTableId1')]", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": + { + "totalRetentionInDays": 30, + "plan": "Analytics", + "retentionInDays": 30, + "schema": { + "name": "[variables('_logAnalyticsTableId1')]", + "tableSubType": "DataCollectionRuleBased", + "tableType": "CustomLog", + "columns": [ + {"name": "alertProvider", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "description", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "id", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "impactScope", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "incidentId", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "indicators", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "investigationResult", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "investigationStatus", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "matchedRules", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "model", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "modelId", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "modelType", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "ownerIds", "type": "dynamic", "isDefaultDisplay": false, "isHidden": false}, + {"name": "schemaVersion", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "score", "type": "int", "isDefaultDisplay": false, "isHidden": false}, + {"name": "severity", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "status", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "updatedDateTime", "type": "datetime", "isDefaultDisplay": false, "isHidden": false}, + {"name": "workbenchLink", "type": "string", "isDefaultDisplay": false, "isHidden": false}, + {"name": "TimeGenerated", "type": "datetime", "isDefaultDisplay": false, "isHidden": false} + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition'),'-', variables('dataConnectorVersionConnectorDefinition'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": + { + "connectorUiConfig": { + "id": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "title": "TrendAI Workbench Alerts", + "publisher": "TrendAI", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "The TrendAI Workbench connector allows you to ingest security alerts from TrendAI Workbench into Microsoft Sentinel.", + "graphQueriesTableName": "[variables('_logAnalyticsTableId1')]", + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "WorkbenchAlert_CL", + "baseQuery": "[variables('_logAnalyticsTableId1')]" + } + ], + "sampleQueries": [ + { + "description": "All Workbench Alerts", + "query": "[concat(variables('_logAnalyticsTableId1'), '\n| sort by TimeGenerated desc')]" + } + ], + "dataTypes": [ + { + "name": "[variables('_logAnalyticsTableId1')]", + "lastDataReceivedQuery": "[concat(variables('_logAnalyticsTableId1'), '\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)')]" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "TrendAI API Key", + "description": "A TrendAI API key is required to connect to the TrendAI Workbench API." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect TrendAI Workbench to Microsoft Sentinel", + "description": "Provide your TrendAI API credentials to establish the connection. Note: Filter is configured during ARM template deployment.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "placeholder": "Enter your TrendAI API Key", + "type": "text", + "name": "apikey" + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectButtonLabel": "Connect", + "disconnectButtonLabel": "Disconnect" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections'), variables('dataConnectorVersionConnections'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]", + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('workspace'), '/providers/Microsoft.SecurityInsights/contentTemplates/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnections'))]", + "contentKind": "ResourcesDataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnections')]", + "parameters": + { + "connectorDefinitionName": { + "defaultValue": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "type": "string", + "minLength": 1 + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "string" + }, + "dcrConfig": { + "type": "object" + }, + "apikey": { + "defaultValue": "", + "type": "securestring" + }, + "tmv1filter": { + "defaultValue": "[parameters('workbenchFilter')]", + "type": "string" + }, + "selectedApiHostname": { + "defaultValue": "[variables('selectedApiHostname')]", + "type": "string" + } + }, + "variables": { + "_dataConnectorContentIdConnections": "[variables('_dataConnectorContentIdConnections')]" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections'))]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorVersionConnections')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'TrendAI-Workbench')]", + "apiVersion": "2022-12-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": + { + "connectorDefinitionName": "[[parameters('connectorDefinitionName')]", + "dataType": "TrendAI Workbench Alerts", + "dcrConfig": { + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]", + "streamName": "Custom-WorkbenchAlert_CL" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[[concat('https://', parameters('selectedApiHostname'), '/v3.0/workbench/alerts')]", + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-dd'T'HH:mm:ss'Z'", + "startTimeAttributeName": "startDateTime", + "endTimeAttributeName": "endDateTime", + "queryWindowInMin": 5, + "headers": "[[if(empty(parameters('tmv1filter')), json('{}'), json(concat('{\"TMV1-Filter\": \"', parameters('tmv1filter'), '\"}')))]", + "rateLimitQPS": 10, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.items" + ], + "format": "json" + }, + "isActive": true + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections'),'-', variables('dataConnectorVersionConnections'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + } + ] +} diff --git a/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function-oat.json b/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function-oat.json new file mode 100644 index 00000000000..acef77c6ee6 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function-oat.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Deploys the TrendMicroOAT_Complete parser function to Log Analytics workspace" + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": {"description": "Log Analytics workspace name"} + }, + "workspace-location": { + "type": "string", + "metadata": {"description": "Workspace Azure region"} + } + }, + "variables": { + "functionName": "TrendMicroOAT_Complete", + "functionAlias": "TrendMicroOAT_Complete", + "category": "TrendMicro", + "functionQuery": "TrendMicro_XDR_OAT_CL\n// Legacy Azure Function connector data is used AS-IS\n// This parser is for the legacy connector only and does not transform data\n// Simply returns all columns from the TrendMicro_XDR_OAT_CL table" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[concat(parameters('workspace'), '/', variables('functionName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "displayName": "[variables('functionName')]", + "category": "[variables('category')]", + "functionAlias": "[variables('functionAlias')]", + "query": "[variables('functionQuery')]", + "version": 2 + } + } + ], + "outputs": { + "functionName": { + "type": "string", + "value": "[variables('functionName')]" + }, + "message": { + "type": "string", + "value": "✅ Parser function deployed! Usage: TrendMicroOAT_Complete() | where detail_filterRiskLevel_s == 'high'" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function.json b/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function.json new file mode 100644 index 00000000000..cc1808ca6ad --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/legacy/deploy-parser-function.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Deploys the TrendMicroWorkbench_Complete parser function to Log Analytics workspace (Legacy connector only)" + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": {"description": "Log Analytics workspace name"} + }, + "workspace-location": { + "type": "string", + "metadata": {"description": "Workspace Azure region"} + } + }, + "variables": { + "functionName": "TrendMicroWorkbench_Complete", + "functionAlias": "TrendMicroWorkbench_Complete", + "category": "TrendMicro", + "functionQuery": "TrendMicro_XDR_WORKBENCH_CL\n// Auto-detect format: use dynamic column if available, otherwise parse string column\n| extend indicators_array = iff(isnull(indicators), parse_json(indicators_s), indicators)\n| extend impactScope_parsed = iff(isnull(entities), parse_json(impactScope_s), dynamic(null))\n| extend entities_array = iff(isnull(entities), impactScope_parsed.entities, entities)\n| extend matchedRules_array = iff(isnull(matchedRules), parse_json(matchedRules_s), matchedRules)\n// Extract count fields from impactScope (only for old data)\n| extend desktopCount_extracted = iff(isnull(entities), toint(impactScope_parsed.desktopCount), toint(desktopCount_d))\n| extend serverCount_extracted = iff(isnull(entities), toint(impactScope_parsed.serverCount), toint(serverCount_d))\n| extend accountCount_extracted = iff(isnull(entities), toint(impactScope_parsed.accountCount), toint(accountCount_d))\n| extend emailAddressCount_extracted = iff(isnull(entities), toint(impactScope_parsed.emailAddressCount), toint(emailAddressCount_d))\n// Step 1: Expand and extract indicators\n| mv-expand indicator = indicators_array\n| extend ind_type = tostring(indicator.type)\n| extend ind_value = tostring(indicator.value)\n| extend ind_field = tostring(indicator.field)\n// Aggregate IOCs by workbenchId\n| summarize\n ProcessCommandLine_s = maxif(ind_value, ind_type == \"command_line\"),\n FileName_s = maxif(ind_value, ind_type == \"filename\"),\n FileHashValue_s = maxif(ind_value, ind_type in (\"file_sha1\", \"file_sha256\", \"md5\")),\n DomainName_s = maxif(ind_value, ind_type == \"domain\"),\n FileDirectory_s = maxif(ind_value, ind_type == \"fullpath\"),\n IPAddress_extracted = maxif(ind_value, ind_type == \"ip\"),\n URL_s = maxif(ind_value, ind_type == \"url\"),\n RegistryKey_s = maxif(ind_value, ind_type == \"registry_key\"),\n RegistryValue_s = maxif(ind_value, ind_type == \"registry_value_data\"),\n RegistryValueName_s = maxif(ind_value, ind_type == \"registry_value\"),\n MalwareName_s = maxif(ind_value, ind_type == \"detection_name\"),\n entities_array = any(entities_array),\n desktopCount_extracted = any(desktopCount_extracted),\n serverCount_extracted = any(serverCount_extracted),\n accountCount_extracted = any(accountCount_extracted),\n emailAddressCount_extracted = any(emailAddressCount_extracted),\n TimeGenerated = any(TimeGenerated),\n SourceSystem = any(SourceSystem),\n MG = any(MG),\n ManagementGroupName = any(ManagementGroupName),\n Computer = any(Computer),\n RawData = any(RawData),\n schemaVersion_s = any(schemaVersion_s),\n investigationStatus_s = any(investigationStatus_s),\n alertStatus_s = any(alertStatus_s),\n investigationResult_s = any(investigationResult_s),\n workbenchLink_s = any(workbenchLink_s),\n alertProvider_s = any(alertProvider_s),\n modelId_g = any(modelId_g),\n modelId_s = any(modelId_s),\n model_s = any(model_s),\n workbenchName_s = any(workbenchName_s),\n modelType_s = any(modelType_s),\n priorityScore_d = any(priorityScore_d),\n severity_s = any(severity_s),\n createdTime_t = any(createdTime_t),\n updatedTime_t = any(updatedTime_t),\n alertTriggerTimestamp_t = any(alertTriggerTimestamp_t),\n workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t),\n incidentId_s = any(incidentId_s),\n description_s = any(description_s),\n desktopCount_d = any(desktopCount_d),\n serverCount_d = any(serverCount_d),\n accountCount_d = any(accountCount_d),\n emailAddressCount_d = any(emailAddressCount_d),\n indicators_s = any(indicators_s),\n impactScope_s = any(impactScope_s),\n impactScope_Summary_s = any(impactScope_Summary_s),\n matchedRules_s = any(matchedRules_s),\n xdrCustomerID_g = any(xdrCustomerID_g),\n TenantId = any(TenantId),\n Type = any(Type),\n _ResourceId = any(_ResourceId)\n by workbenchId_s\n// Step 2: Expand and extract entities\n| mv-expand entity = entities_array\n| extend ent_type = tostring(entity.entityType)\n| extend ent_value = entity.entityValue\n| extend ent_value_str = tostring(entity.entityValue)\n| extend ent_value_name = tostring(entity.entityValue.name)\n| summarize\n HostHostName_s = maxif(ent_value_name, ent_type == \"host\"),\n UserAccountFull = maxif(ent_value_str, ent_type == \"account\" and ent_value_str contains \"\\\\\"),\n MailboxPrimaryAddress_s = maxif(ent_value_str, ent_type == \"emailAddress\"),\n ProcessCommandLine_s = any(ProcessCommandLine_s),\n FileName_s = any(FileName_s),\n FileHashValue_s = any(FileHashValue_s),\n DomainName_s = any(DomainName_s),\n FileDirectory_s = any(FileDirectory_s),\n IPAddress_extracted = any(IPAddress_extracted),\n URL_s = any(URL_s),\n RegistryKey_s = any(RegistryKey_s),\n RegistryValue_s = any(RegistryValue_s),\n RegistryValueName_s = any(RegistryValueName_s),\n MalwareName_s = any(MalwareName_s),\n desktopCount_extracted = any(desktopCount_extracted),\n serverCount_extracted = any(serverCount_extracted),\n accountCount_extracted = any(accountCount_extracted),\n emailAddressCount_extracted = any(emailAddressCount_extracted),\n TimeGenerated = any(TimeGenerated),\n SourceSystem = any(SourceSystem),\n MG = any(MG),\n ManagementGroupName = any(ManagementGroupName),\n Computer = any(Computer),\n RawData = any(RawData),\n schemaVersion_s = any(schemaVersion_s),\n investigationStatus_s = any(investigationStatus_s),\n alertStatus_s = any(alertStatus_s),\n investigationResult_s = any(investigationResult_s),\n workbenchLink_s = any(workbenchLink_s),\n alertProvider_s = any(alertProvider_s),\n modelId_g = any(modelId_g),\n modelId_s = any(modelId_s),\n model_s = any(model_s),\n workbenchName_s = any(workbenchName_s),\n modelType_s = any(modelType_s),\n priorityScore_d = any(priorityScore_d),\n severity_s = any(severity_s),\n createdTime_t = any(createdTime_t),\n updatedTime_t = any(updatedTime_t),\n alertTriggerTimestamp_t = any(alertTriggerTimestamp_t),\n workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t),\n incidentId_s = any(incidentId_s),\n description_s = any(description_s),\n desktopCount_d = any(desktopCount_d),\n serverCount_d = any(serverCount_d),\n accountCount_d = any(accountCount_d),\n emailAddressCount_d = any(emailAddressCount_d),\n indicators_s = any(indicators_s),\n impactScope_s = any(impactScope_s),\n impactScope_Summary_s = any(impactScope_Summary_s),\n matchedRules_s = any(matchedRules_s),\n xdrCustomerID_g = any(xdrCustomerID_g),\n TenantId = any(TenantId),\n Type = any(Type),\n _ResourceId = any(_ResourceId)\n by workbenchId_s\n// Step 3: Parse domain\\username and apply defaults\n| extend UserAccountNTDomain_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, \"\\\\\")[0], \"[]\")\n| extend UserAccountName_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, \"\\\\\")[1], \"[]\")\n| extend\n FileName_s = coalesce(FileName_s, \"[]\"),\n FileHashValue_s = coalesce(FileHashValue_s, \"[]\"),\n DomainName_s = coalesce(DomainName_s, \"[]\"),\n FileDirectory_s = coalesce(FileDirectory_s, \"[]\"),\n IPAddress = coalesce(IPAddress_extracted, \"[]\"),\n URL_s = coalesce(URL_s, \"[]\"),\n HostHostName_s = coalesce(HostHostName_s, \"[]\"),\n ProcessCommandLine_s = coalesce(ProcessCommandLine_s, \"[]\"),\n RegistryKey_s = coalesce(RegistryKey_s, \"[]\"),\n RegistryValue_s = coalesce(RegistryValue_s, \"[]\"),\n RegistryValueName_s = coalesce(RegistryValueName_s, \"[]\"),\n MailboxPrimaryAddress_s = coalesce(MailboxPrimaryAddress_s, \"[]\"),\n MalwareName_s = coalesce(MalwareName_s, \"[]\"),\n desktopCount_d = coalesce(desktopCount_extracted, 0),\n serverCount_d = coalesce(serverCount_extracted, 0),\n accountCount_d = coalesce(accountCount_extracted, 0),\n emailAddressCount_d = coalesce(emailAddressCount_extracted, 0)\n| project\n TimeGenerated,\n SourceSystem,\n MG,\n ManagementGroupName,\n Computer,\n RawData,\n FileName_s,\n FileHashValue_s,\n DomainName_s,\n FileDirectory_s,\n IPAddress,\n URL_s,\n HostHostName_s,\n ProcessCommandLine_s,\n RegistryKey_s,\n RegistryValue_s,\n RegistryValueName_s,\n UserAccountNTDomain_s,\n UserAccountName_s,\n alertProvider_s,\n alertTriggerTimestamp_t,\n createdTime_t,\n description_s,\n impactScope_s,\n impactScope_Summary_s,\n indicators_s,\n investigationStatus_s,\n matchedRules_s,\n model_s,\n modelId_g,\n modelId_s,\n priorityScore_d,\n severity_s,\n updatedTime_t,\n workbenchCompleteTimestamp_t,\n workbenchId_s,\n workbenchLink_s,\n workbenchName_s,\n xdrCustomerID_g,\n MailboxPrimaryAddress_s,\n MalwareName_s,\n schemaVersion_s,\n alertStatus_s,\n investigationResult_s,\n modelType_s,\n incidentId_s,\n desktopCount_d,\n serverCount_d,\n accountCount_d,\n emailAddressCount_d,\n Type,\n TenantId,\n _ResourceId" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[concat(parameters('workspace'), '/', variables('functionName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "displayName": "[variables('functionName')]", + "category": "[variables('category')]", + "functionAlias": "[variables('functionAlias')]", + "query": "[variables('functionQuery')]", + "version": 2 + } + } + ], + "outputs": { + "functionName": { + "type": "string", + "value": "[variables('functionName')]" + }, + "message": { + "type": "string", + "value": "✅ Parser function deployed! Usage: TrendMicroWorkbench_Complete() | where severity_s == 'critical'" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/components/connector-definition.json b/Solutions/TrendAI Vision One/templates/oat/components/connector-definition.json new file mode 100644 index 00000000000..3f3e9f205ee --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/connector-definition.json @@ -0,0 +1,111 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + } + }, + "variables": { + "connectorId": "TrendMicro_XDR_OAT" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'))]", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "[variables('connectorId')]", + "title": "Trend Micro Vision One - OAT", + "publisher": "Trend Micro", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "**V1-compatible** CCF connector for Observed Attack Techniques. Column names exactly match the legacy V1 Azure Function connector (detail_*_s prefix, endpoint_ips_s/endpoint_name_s/endpoint_guid_g object expansion, xdrCustomerId_g lowercase). Full payload also preserved as `RawData` for fallback parsing.", + "graphQueriesTableName": "TrendMicro_XDR_OAT_V2_CL", + "dataTypes": [ + { + "name": "TrendMicro_XDR_OAT_V2_CL", + "lastDataReceivedQuery": "TrendMicro_XDR_OAT_V2_CL | summarize Time = max(TimeGenerated) | where isnotempty(Time)" + } + ], + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "TrendMicro_XDR_OAT_V2_CL", + "baseQuery": "TrendMicro_XDR_OAT_V2_CL" + } + ], + "sampleQueries": [ + { + "description": "All OAT Detections", + "query": "TrendMicro_XDR_OAT_V2_CL | sort by TimeGenerated desc | take 10" + }, + { + "description": "High Risk Credential Dumping (V1-compatible)", + "query": "TrendMicro_XDR_OAT_V2_CL | where detail_filterRiskLevel_s == 'high' | project TimeGenerated, detail_endpointHostName_s, detail_processCmd_s, detail_objectCmd_s, detail_processFileHashSha256_s" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions required", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ] + }, + "instructionSteps": [ + { + "title": "1. Get API Token", + "description": "Obtain your Trend Micro Vision One API token from the Administration Console", + "instructions": [ + { + "type": "InfoMessage", + "parameters": { + "text": "Log in to Trend Micro Vision One Console \u2192 Administration \u2192 API Keys \u2192 Generate new API key with 'SIEM' role permissions" + } + } + ] + }, + { + "title": "2. Connect via Azure Portal", + "description": "Deploy the connection using the button below", + "instructions": [ + { + "type": "InstallAgent", + "parameters": {} + } + ] + } + ] + } + } + } + ], + "outputs": { + "connectorId": { + "type": "string", + "value": "[variables('connectorId')]" + } + } +} \ No newline at end of file diff --git a/Solutions/TrendAI Vision One/templates/oat/components/data-connector.json b/Solutions/TrendAI Vision One/templates/oat/components/data-connector.json new file mode 100644 index 00000000000..d45d0a20263 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/data-connector.json @@ -0,0 +1,114 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + }, + "apikey": { + "type": "securestring", + "metadata": { + "description": "Trend Vision One API token (without 'Bearer' prefix)." + } + }, + "trendaiRegion": { + "type": "string", + "allowedValues": [ "UK", "US", "SG", "CA", "JP" ], + "metadata": { + "description": "Trend Vision One region where the tenant is hosted." + } + }, + "oatFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter expression. Example: (riskLevel eq 'high'). Leave empty for no filter." + } + }, + "dceEndpoint": { + "type": "string", + "metadata": { + "description": "Logs-ingestion endpoint URL of the Data Collection Endpoint." + } + }, + "dcrImmutableId": { + "type": "string", + "metadata": { + "description": "Immutable ID of the Data Collection Rule." + } + }, + "streamName": { + "type": "string", + "metadata": { + "description": "Stream name declared by the DCR (e.g. Custom-TrendMicro_XDR_OAT_V2_CL)." + } + } + }, + "variables": { + "connectorId": "TrendMicro_XDR_OAT", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'), '-connection')]", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[variables('connectorId')]", + "dataType": "TrendMicro_XDR_OAT_V2_CL", + "dcrConfig": { + "streamName": "[parameters('streamName')]", + "dataCollectionEndpoint": "[parameters('dceEndpoint')]", + "dataCollectionRuleImmutableId": "[parameters('dcrImmutableId')]" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[concat('https://', variables('apiHostnames')[parameters('trendaiRegion')], '/v3.0/oat/detections')]", + "rateLimitQPS": 10, + "queryWindowInMin": 5, + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-dd'T'HH:mm:ss'Z'", + "startTimeAttributeName": "detectedStartDateTime", + "endTimeAttributeName": "detectedEndDateTime", + "queryParameters": { + "top": "500" + }, + "headers": "[if(empty(parameters('oatFilter')), json('{}'), json(concat('{\"TMV1-Filter\": \"', parameters('oatFilter'), '\"}')))]", + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.items" + ], + "format": "json" + }, + "paging": { + "pagingType": "LinkHeader", + "linkHeaderTokenJsonPath": "$.nextLink" + } + } + } + ], + "outputs": { + "connectorId": { + "type": "string", + "value": "[variables('connectorId')]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/components/dce.json b/Solutions/TrendAI Vision One/templates/oat/components/dce.json new file mode 100644 index 00000000000..aa0381f73d2 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/dce.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace-location": { + "type": "string" + } + }, + "variables": { + "dceName": "TrendMicro-XDR-OAT-DCE" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dceName')]", + "location": "[parameters('workspace-location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + } + ], + "outputs": { + "dceId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]" + }, + "dceName": { + "type": "string", + "value": "[variables('dceName')]" + }, + "dceEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName')), '2021-09-01-preview').logsIngestion.endpoint]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/components/dcr.json b/Solutions/TrendAI Vision One/templates/oat/components/dcr.json new file mode 100644 index 00000000000..a8ee97d2728 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/dcr.json @@ -0,0 +1,125 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + }, + "dceName": { + "type": "string" + }, + "tableName": { + "type": "string" + }, + "excludeThirdPartyOat": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Exclude OAT detections from third-party linked sources (productCode == 'tlc'). Defaults to true. Set false to ingest all sources including third-party." + } + } + }, + "variables": { + "dcrName": "TrendMicro-XDR-OAT-DCR", + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "oatTransformBody": "TimeGenerated = detectedDateTime, SourceSystem = 'RestAPI', Computer = '', RawData = tostring(detail), detectionTime_t = todatetime(detectedDateTime), entityType_s = tostring(entityType), entityName_s = tostring(entityName), filters_s = tostring(filters), endpoint_ips_s = tostring(endpoint.ips), endpoint_name_s = tostring(endpoint.endpointName), endpoint_guid_g = tostring(endpoint.agentGuid), xdrCustomerId_g = '', detail_endpointGuid_g = tostring(d.endpointGuid), detail_eventId_s = tostring(d.eventId), detail_eventSubId_s = tostring(d.eventSubId), detail_firstSeen_t = todatetime(datetime(1970-01-01) + tolong(d.firstSeen) * 1ms), detail_lastSeen_t = todatetime(datetime(1970-01-01) + tolong(d.lastSeen) * 1ms), detail_logonUser_s = tostring(d.logonUser), detail_objectCmd_s = tostring(d.objectCmd), detail_objectFileCreation_d = toreal(d.objectFileCreation), detail_objectFileHashSha256_s = tostring(d.objectFileHashSha256), detail_objectFileModifiedTime_d = toreal(d.objectFileModifiedTime), detail_objectFileSize_d = toreal(d.objectFileSize), detail_objectLaunchTime_d = toreal(d.objectLaunchTime), detail_objectName_s = tostring(d.objectName), detail_objectRunAsLocalAccount_b = tobool(d.objectRunAsLocalAccount), detail_objectSigner_s = tostring(d.objectSigner), detail_objectSignerValid_s = tostring(d.objectSignerValid), detail_objectTrueType_d = toreal(d.objectTrueType), detail_objectUser_s = tostring(d.objectUser), detail_objectUserDomain_s = tostring(d.objectUserDomain), detail_osName_s = tostring(d.osName), detail_osType_s = tostring(d.osType), detail_osVer_s = tostring(d.osVer), detail_parentCmd_s = tostring(d.parentCmd), detail_parentFileCreation_d = toreal(d.parentFileCreation), detail_parentFileHashSha1_s = tostring(d.parentFileHashSha1), detail_parentFileHashSha256_s = tostring(d.parentFileHashSha256), detail_parentFileModifiedTime_d = toreal(d.parentFileModifiedTime), detail_parentFilePath_s = tostring(d.parentFilePath), detail_parentFileSize_d = toreal(d.parentFileSize), detail_parentLaunchTime_d = toreal(d.parentLaunchTime), detail_parentName_s = tostring(d.parentName), detail_parentTrueType_d = toreal(d.parentTrueType), detail_parentUser_s = tostring(d.parentUser), detail_parentUserDomain_s = tostring(d.parentUserDomain), detail_plang_d = toreal(d.plang), detail_processCmd_s = tostring(d.processCmd), detail_processFileCreation_d = toreal(d.processFileCreation), detail_processFileHashSha1_s = tostring(d.processFileHashSha1), detail_processFileHashSha256_s = tostring(d.processFileHashSha256), detail_processFileModifiedTime_d = toreal(d.processFileModifiedTime), detail_processFilePath_s = tostring(d.processFilePath), detail_processFileSize_d = toreal(d.processFileSize), detail_processLaunchTime_d = toreal(d.processLaunchTime), detail_processPid_d = toreal(d.processPid), detail_processSigner_s = tostring(d.processSigner), detail_processSignerValid_s = tostring(d.processSignerValid), detail_processTrueType_d = toreal(d.processTrueType), detail_processUser_s = tostring(d.processUser), detail_processUserDomain_s = tostring(d.processUserDomain), detail_timezone_s = tostring(d.timezone), detail_userDomain_s = tostring(d.userDomain), detail_objectAppName_s = tostring(d.objectAppName), detail_objectContentName_s = tostring(d.objectContentName), detail_objectFirstSeen_d = toreal(d.objectFirstSeen), detail_objectLastSeen_d = toreal(d.objectLastSeen), detail_objectRawDataStr_s = tostring(d.objectRawDataStr), detail_parentSigner_s = tostring(d.parentSigner), detail_parentSignerValid_s = tostring(d.parentSignerValid), detail_objectSubTrueType_d = toreal(d.objectSubTrueType), detail_hostName_s = tostring(d.hostName), detail_objectIps_s = tostring(d.objectIps), detail_srcFirstSeen_d = toreal(d.srcFirstSeen), detail_srcLastSeen_d = toreal(d.srcLastSeen), detail_actResult_s = tostring(d.actResult), detail_channel_s = tostring(d.channel), detail_domainName_s = tostring(d.domainName), detail_endpointMacAddress_s = tostring(d.endpointMacAddress), detail_eventSubName_s = tostring(d.eventSubName), detail_firstAct_s = tostring(d.firstAct), detail_firstActResult_s = tostring(d.firstActResult), detail_mDevice_s = tostring(d.mDevice), detail_malDst_s = tostring(d.malDst), detail_malName_s = tostring(d.malName), detail_malSubType_s = tostring(d.malSubType), detail_objectFileHashSha1_s = tostring(d.objectFileHashSha1), detail_objectFileName_s = tostring(d.objectFileName), detail_objectFilePath_s = tostring(d.objectFilePath), detail_objectType_s = tostring(d.objectType), detail_scanType_s = tostring(d.scanType), detail_secondAct_s = tostring(d.secondAct), detail_secondActResult_s = tostring(d.secondActResult), detail_act_s = tostring(d.act), detail_aggregatedCount_d = toreal(d.aggregatedCount), detail_app_s = tostring(d.app), detail_appGroup_s = tostring(d.appGroup), detail_aptRelated_s = tostring(d.aptRelated), detail_clientFlag_s = tostring(d.clientFlag), detail_detectionType_s = tostring(d.detectionType), detail_deviceDirection_s = tostring(d.deviceDirection), detail_deviceGUID_g = tostring(d.deviceGUID), detail_deviceMacAddress_s = tostring(d.deviceMacAddress), detail_dhost_s = tostring(d.dhost), detail_dmac_s = tostring(d.dmac), detail_dpt_d = toreal(d.dpt), detail_dst_s = tostring(d.dst), detail_dstGroup_s = tostring(d.dstGroup), detail_dstZone_s = tostring(d.dstZone), detail_dvchost_s = tostring(d.dvchost), detail_eventId_d = toreal(d.eventId), detail_eventName_s = tostring(d.eventName), detail_eventSourceType_s = tostring(d.eventSourceType), detail_eventTime_d = toreal(d.eventTime), detail_fileExt_s = tostring(d.fileExt), detail_fileHash_s = tostring(d.fileHash), detail_fileName_s = tostring(d.fileName), detail_filePath_s = tostring(d.filePath), detail_filePathName_s = tostring(d.filePathName), detail_fileSize_d = toreal(d.fileSize), detail_filterRiskLevel_s = tostring(d.filterRiskLevel), detail_fullPath_s = tostring(d.fullPath), detail_hostSeverity_d = toreal(d.hostSeverity), detail_interestedGroup_s = tostring(d.interestedGroup), detail_interestedHost_s = tostring(d.interestedHost), detail_interestedIp_s = tostring(d.interestedIp), detail_malType_s = tostring(d.malType), detail_malTypeGroup_s = tostring(d.malTypeGroup), detail_pAttackPhase_s = tostring(d.pAttackPhase), detail_pComp_s = tostring(d.pComp), detail_peerGroup_s = tostring(d.peerGroup), detail_peerHost_s = tostring(d.peerHost), detail_peerIp_s = tostring(d.peerIp), detail_pname_s = tostring(d.pname), detail_remarks_s = tostring(d.remarks), detail_rt_t = todatetime(datetime(1970-01-01) + tolong(d.rt) * 1ms), detail_rtHour_d = toreal(d.rtHour), detail_ruleId_d = toreal(d.ruleId), detail_ruleName_s = tostring(d.ruleName), detail_senderIp_s = tostring(d.senderIp), detail_severity_d = toreal(d.severity), detail_shost_s = tostring(d.shost), detail_smac_s = tostring(d.smac), detail_spt_d = toreal(d.spt), detail_src_s = tostring(d.src), detail_srcGroup_s = tostring(d.srcGroup), detail_srcZone_s = tostring(d.srcZone), detail_tags_s = tostring(d.tags), detail_threatType_s = tostring(d.threatType), detail_uuid_g = tostring(d.uuid), detail_cat_d = toreal(d.cat), detail_endpointGUID_g = tostring(d.endpointGUID), detail_endpointHostName_s = tostring(d.endpointHostName), detail_endpointIp_s = tostring(d.endpointIp), detail_processName_s = tostring(d.processName), detail_proto_s = tostring(d.proto)" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dcrName')]", + "location": "[parameters('workspace-location')]", + "properties": { + "dataCollectionEndpointId": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('dceName'))]", + "streamDeclarations": { + "Custom-TrendMicro_XDR_OAT_V2_CL": { + "columns": [ + { + "name": "source", + "type": "string" + }, + { + "name": "uuid", + "type": "string" + }, + { + "name": "detectedDateTime", + "type": "datetime" + }, + { + "name": "ingestedDateTime", + "type": "datetime" + }, + { + "name": "entityType", + "type": "string" + }, + { + "name": "entityName", + "type": "string" + }, + { + "name": "productCode", + "type": "string" + }, + { + "name": "endpoint", + "type": "dynamic" + }, + { + "name": "filters", + "type": "dynamic" + }, + { + "name": "detail", + "type": "dynamic" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-TrendMicro_XDR_OAT_V2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "[concat('source | extend d = detail', if(parameters('excludeThirdPartyOat'), ' | where tostring(productCode) != ''tlc''', ''), ' | extend ', variables('oatTransformBody'))]", + "outputStream": "Custom-TrendMicro_XDR_OAT_V2_CL" + } + ] + } + } + ], + "outputs": { + "dcrId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName'))]" + }, + "dcrName": { + "type": "string", + "value": "[variables('dcrName')]" + }, + "dcrImmutableId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName')), '2021-09-01-preview').immutableId]" + }, + "streamName": { + "type": "string", + "value": "Custom-TrendMicro_XDR_OAT_V2_CL" + } + } +} \ No newline at end of file diff --git a/Solutions/TrendAI Vision One/templates/oat/components/parser-function.json b/Solutions/TrendAI Vision One/templates/oat/components/parser-function.json new file mode 100644 index 00000000000..ab933283cd7 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/parser-function.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Deploys the TrendMicroOAT_Complete parser function to Log Analytics workspace" + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Workspace Azure region" + } + } + }, + "variables": { + "functionName": "TrendMicroOAT_Complete", + "functionAlias": "TrendMicroOAT_Complete", + "category": "TrendMicro", + "functionQuery": "union isfuzzy=true\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // LEGACY DATA (Azure Function): Use AS-IS (already in correct format)\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n (TrendMicro_XDR_OAT_CL\n | extend source_table = \"legacy\"\n ),\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // V2 DATA (CCF Connector): Use AS-IS (schema should match legacy)\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n (TrendMicro_XDR_OAT_V2_CL\n | extend source_table = \"ccf\"\n )\n" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[concat(parameters('workspace'), '/', variables('functionName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "displayName": "[variables('functionName')]", + "category": "[variables('category')]", + "functionAlias": "[variables('functionAlias')]", + "query": "[variables('functionQuery')]", + "version": 2 + } + } + ], + "outputs": { + "functionName": { + "type": "string", + "value": "[variables('functionName')]" + }, + "message": { + "type": "string", + "value": "\u2705 Parser function deployed! Usage: TrendMicroOAT_Complete() | where detail_filterRiskLevel_s == 'high'" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/components/sentinel-solution.json b/Solutions/TrendAI Vision One/templates/oat/components/sentinel-solution.json new file mode 100644 index 00000000000..834f44d5bc5 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/sentinel-solution.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + } + }, + "variables": { + "solutionId": "trendmicro.trendmicro-xdr-oat-solution", + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[concat('SecurityInsights', '(', parameters('workspace'), ')')]", + "location": "[parameters('workspace-location')]", + "plan": { + "name": "[concat('SecurityInsights', '(', parameters('workspace'), ')')]", + "publisher": "Microsoft", + "product": "OMSGallery/SecurityInsights", + "promotionCode": "" + }, + "properties": { + "workspaceResourceId": "[variables('workspaceResourceId')]" + } + } + ], + "outputs": { + "solutionId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationsManagement/solutions', concat('SecurityInsights', '(', parameters('workspace'), ')'))]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/components/table.json b/Solutions/TrendAI Vision One/templates/oat/components/table.json new file mode 100644 index 00000000000..1ef75752288 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/components/table.json @@ -0,0 +1,196 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + } + }, + "variables": { + "tableName": "TrendMicro_XDR_OAT_V2_CL" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[concat(parameters('workspace'), '/', variables('tableName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "schema": { + "name": "[variables('tableName')]", + "columns": [ + {"name": "TimeGenerated", "type": "datetime"}, + {"name": "SourceSystem", "type": "string"}, + {"name": "Computer", "type": "string"}, + {"name": "RawData", "type": "string"}, + {"name": "detectionTime_t", "type": "datetime"}, + {"name": "entityType_s", "type": "string"}, + {"name": "entityName_s", "type": "string"}, + {"name": "filters_s", "type": "string"}, + {"name": "endpoint_ips_s", "type": "string"}, + {"name": "endpoint_name_s", "type": "string"}, + {"name": "endpoint_guid_g", "type": "string"}, + {"name": "xdrCustomerId_g", "type": "string"}, + {"name": "detail_endpointGuid_g", "type": "string"}, + {"name": "detail_eventId_s", "type": "string"}, + {"name": "detail_eventSubId_s", "type": "string"}, + {"name": "detail_firstSeen_t", "type": "datetime"}, + {"name": "detail_lastSeen_t", "type": "datetime"}, + {"name": "detail_logonUser_s", "type": "string"}, + {"name": "detail_objectCmd_s", "type": "string"}, + {"name": "detail_objectFileCreation_d", "type": "real"}, + {"name": "detail_objectFileHashSha256_s", "type": "string"}, + {"name": "detail_objectFileModifiedTime_d", "type": "real"}, + {"name": "detail_objectFileSize_d", "type": "real"}, + {"name": "detail_objectLaunchTime_d", "type": "real"}, + {"name": "detail_objectName_s", "type": "string"}, + {"name": "detail_objectRunAsLocalAccount_b", "type": "boolean"}, + {"name": "detail_objectSigner_s", "type": "string"}, + {"name": "detail_objectSignerValid_s", "type": "string"}, + {"name": "detail_objectTrueType_d", "type": "real"}, + {"name": "detail_objectUser_s", "type": "string"}, + {"name": "detail_objectUserDomain_s", "type": "string"}, + {"name": "detail_osName_s", "type": "string"}, + {"name": "detail_osType_s", "type": "string"}, + {"name": "detail_osVer_s", "type": "string"}, + {"name": "detail_parentCmd_s", "type": "string"}, + {"name": "detail_parentFileCreation_d", "type": "real"}, + {"name": "detail_parentFileHashSha1_s", "type": "string"}, + {"name": "detail_parentFileHashSha256_s", "type": "string"}, + {"name": "detail_parentFileModifiedTime_d", "type": "real"}, + {"name": "detail_parentFilePath_s", "type": "string"}, + {"name": "detail_parentFileSize_d", "type": "real"}, + {"name": "detail_parentLaunchTime_d", "type": "real"}, + {"name": "detail_parentName_s", "type": "string"}, + {"name": "detail_parentTrueType_d", "type": "real"}, + {"name": "detail_parentUser_s", "type": "string"}, + {"name": "detail_parentUserDomain_s", "type": "string"}, + {"name": "detail_plang_d", "type": "real"}, + {"name": "detail_processCmd_s", "type": "string"}, + {"name": "detail_processFileCreation_d", "type": "real"}, + {"name": "detail_processFileHashSha1_s", "type": "string"}, + {"name": "detail_processFileHashSha256_s", "type": "string"}, + {"name": "detail_processFileModifiedTime_d", "type": "real"}, + {"name": "detail_processFilePath_s", "type": "string"}, + {"name": "detail_processFileSize_d", "type": "real"}, + {"name": "detail_processLaunchTime_d", "type": "real"}, + {"name": "detail_processPid_d", "type": "real"}, + {"name": "detail_processSigner_s", "type": "string"}, + {"name": "detail_processSignerValid_s", "type": "string"}, + {"name": "detail_processTrueType_d", "type": "real"}, + {"name": "detail_processUser_s", "type": "string"}, + {"name": "detail_processUserDomain_s", "type": "string"}, + {"name": "detail_timezone_s", "type": "string"}, + {"name": "detail_userDomain_s", "type": "string"}, + {"name": "detail_objectAppName_s", "type": "string"}, + {"name": "detail_objectContentName_s", "type": "string"}, + {"name": "detail_objectFirstSeen_d", "type": "real"}, + {"name": "detail_objectLastSeen_d", "type": "real"}, + {"name": "detail_objectRawDataStr_s", "type": "string"}, + {"name": "detail_parentSigner_s", "type": "string"}, + {"name": "detail_parentSignerValid_s", "type": "string"}, + {"name": "detail_objectSubTrueType_d", "type": "real"}, + {"name": "detail_hostName_s", "type": "string"}, + {"name": "detail_objectIps_s", "type": "string"}, + {"name": "detail_srcFirstSeen_d", "type": "real"}, + {"name": "detail_srcLastSeen_d", "type": "real"}, + {"name": "detail_actResult_s", "type": "string"}, + {"name": "detail_channel_s", "type": "string"}, + {"name": "detail_domainName_s", "type": "string"}, + {"name": "detail_endpointMacAddress_s", "type": "string"}, + {"name": "detail_eventSubName_s", "type": "string"}, + {"name": "detail_firstAct_s", "type": "string"}, + {"name": "detail_firstActResult_s", "type": "string"}, + {"name": "detail_mDevice_s", "type": "string"}, + {"name": "detail_malDst_s", "type": "string"}, + {"name": "detail_malName_s", "type": "string"}, + {"name": "detail_malSubType_s", "type": "string"}, + {"name": "detail_objectFileHashSha1_s", "type": "string"}, + {"name": "detail_objectFileName_s", "type": "string"}, + {"name": "detail_objectFilePath_s", "type": "string"}, + {"name": "detail_objectType_s", "type": "string"}, + {"name": "detail_scanType_s", "type": "string"}, + {"name": "detail_secondAct_s", "type": "string"}, + {"name": "detail_secondActResult_s", "type": "string"}, + {"name": "detail_act_s", "type": "string"}, + {"name": "detail_aggregatedCount_d", "type": "real"}, + {"name": "detail_app_s", "type": "string"}, + {"name": "detail_appGroup_s", "type": "string"}, + {"name": "detail_aptRelated_s", "type": "string"}, + {"name": "detail_clientFlag_s", "type": "string"}, + {"name": "detail_detectionType_s", "type": "string"}, + {"name": "detail_deviceDirection_s", "type": "string"}, + {"name": "detail_deviceGUID_g", "type": "string"}, + {"name": "detail_deviceMacAddress_s", "type": "string"}, + {"name": "detail_dhost_s", "type": "string"}, + {"name": "detail_dmac_s", "type": "string"}, + {"name": "detail_dpt_d", "type": "real"}, + {"name": "detail_dst_s", "type": "string"}, + {"name": "detail_dstGroup_s", "type": "string"}, + {"name": "detail_dstZone_s", "type": "string"}, + {"name": "detail_dvchost_s", "type": "string"}, + {"name": "detail_eventId_d", "type": "real"}, + {"name": "detail_eventName_s", "type": "string"}, + {"name": "detail_eventSourceType_s", "type": "string"}, + {"name": "detail_eventTime_d", "type": "real"}, + {"name": "detail_fileExt_s", "type": "string"}, + {"name": "detail_fileHash_s", "type": "string"}, + {"name": "detail_fileName_s", "type": "string"}, + {"name": "detail_filePath_s", "type": "string"}, + {"name": "detail_filePathName_s", "type": "string"}, + {"name": "detail_fileSize_d", "type": "real"}, + {"name": "detail_filterRiskLevel_s", "type": "string"}, + {"name": "detail_fullPath_s", "type": "string"}, + {"name": "detail_hostSeverity_d", "type": "real"}, + {"name": "detail_interestedGroup_s", "type": "string"}, + {"name": "detail_interestedHost_s", "type": "string"}, + {"name": "detail_interestedIp_s", "type": "string"}, + {"name": "detail_malType_s", "type": "string"}, + {"name": "detail_malTypeGroup_s", "type": "string"}, + {"name": "detail_pAttackPhase_s", "type": "string"}, + {"name": "detail_pComp_s", "type": "string"}, + {"name": "detail_peerGroup_s", "type": "string"}, + {"name": "detail_peerHost_s", "type": "string"}, + {"name": "detail_peerIp_s", "type": "string"}, + {"name": "detail_pname_s", "type": "string"}, + {"name": "detail_remarks_s", "type": "string"}, + {"name": "detail_rt_t", "type": "datetime"}, + {"name": "detail_rtHour_d", "type": "real"}, + {"name": "detail_ruleId_d", "type": "real"}, + {"name": "detail_ruleName_s", "type": "string"}, + {"name": "detail_senderIp_s", "type": "string"}, + {"name": "detail_severity_d", "type": "real"}, + {"name": "detail_shost_s", "type": "string"}, + {"name": "detail_smac_s", "type": "string"}, + {"name": "detail_spt_d", "type": "real"}, + {"name": "detail_src_s", "type": "string"}, + {"name": "detail_srcGroup_s", "type": "string"}, + {"name": "detail_srcZone_s", "type": "string"}, + {"name": "detail_tags_s", "type": "string"}, + {"name": "detail_threatType_s", "type": "string"}, + {"name": "detail_uuid_g", "type": "string"}, + {"name": "detail_cat_d", "type": "real"}, + {"name": "detail_endpointGUID_g", "type": "string"}, + {"name": "detail_endpointHostName_s", "type": "string"}, + {"name": "detail_endpointIp_s", "type": "string"}, + {"name": "detail_processName_s", "type": "string"}, + {"name": "detail_proto_s", "type": "string"} + ] + } + } + } + ], + "outputs": { + "tableName": { + "type": "string", + "value": "[variables('tableName')]" + }, + "tableId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/createUiDefinition.json b/Solutions/TrendAI Vision One/templates/oat/createUiDefinition.json new file mode 100644 index 00000000000..d14b9100a8a --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/createUiDefinition.json @@ -0,0 +1,149 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "isWizard": false, + "basics": { + "description": "**Trend Vision One - OAT (Observed Attack Techniques)** data connector ingests MITRE ATT&CK mapped detections from Trend Micro Vision One into Microsoft Sentinel.\n\n**Data ingestion:** Observed Attack Techniques with full process trees, file hashes, network indicators, and MITRE ATT&CK mappings.\n\n**Provide your Trend Vision One API token during deployment to enable the live poller.** If you leave it blank, the connector definition and supporting resources still deploy and you can attach credentials later from the Sentinel portal.", + "subscription": { + "constraints": { + "validations": [] + }, + "resourceProviders": [ + "Microsoft.OperationalInsights", + "Microsoft.SecurityInsights", + "Microsoft.Insights", + "Microsoft.OperationsManagement" + ] + }, + "resourceGroup": { + "constraints": {}, + "allowExisting": true + }, + "location": { + "label": "Location", + "toolTip": "Location for all resources", + "resourceTypes": [ + "Microsoft.OperationalInsights/workspaces" + ] + } + } + }, + "basics": [ + { + "name": "getLAWorkspace", + "type": "Microsoft.Solutions.ArmApiControl", + "toolTip": "This filters by workspaces that exist in the Resource Group selected", + "condition": "[greater(length(resourceGroup().name),0)]", + "request": { + "method": "GET", + "path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]" + } + }, + { + "name": "workspace", + "type": "Microsoft.Common.DropDown", + "label": "Workspace", + "placeholder": "Select a workspace", + "toolTip": "Select the Microsoft Sentinel workspace where you want to install the solution", + "constraints": { + "allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + }, + "visible": true + } + ], + "steps": [ + { + "name": "trendConfig", + "label": "Trend Vision One Configuration", + "elements": [ + { + "name": "trendaiRegion", + "type": "Microsoft.Common.DropDown", + "label": "Trend Vision One Region", + "defaultValue": "United States", + "toolTip": "Select the region where your Trend Vision One tenant is hosted", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "United States", + "value": "US" + }, + { + "label": "United Kingdom / European Union", + "value": "UK" + }, + { + "label": "Singapore / Asia Pacific", + "value": "SG" + }, + { + "label": "Canada", + "value": "CA" + }, + { + "label": "Japan", + "value": "JP" + } + ] + } + }, + { + "name": "apiKeyInfo", + "type": "Microsoft.Common.InfoBox", + "options": { + "icon": "Info", + "text": "Generate your API token from: Trend Vision One Console → Administration → API Keys (SIEM role). Paste it below to enable the poller at deploy time. Leave it blank to defer credentials and attach them later via the Sentinel portal." + } + }, + { + "name": "apikey", + "type": "Microsoft.Common.PasswordBox", + "label": { + "password": "Trend Vision One API Token", + "confirmPassword": "Confirm API Token" + }, + "toolTip": "Bearer token (without the 'Bearer' prefix). Leave blank to skip the live poller; the rest of the connector still deploys.", + "constraints": { + "required": false, + "regex": "", + "validationMessage": "" + }, + "options": { + "hideConfirmation": true + } + }, + { + "name": "oatFilter", + "type": "Microsoft.Common.TextBox", + "label": "Optional TMV1-Filter", + "defaultValue": "", + "toolTip": "Optional TMV1-Filter expression sent on every OAT API call. Example: (riskLevel eq 'high'). Leave empty for no filter.", + "constraints": { + "required": false + } + }, + { + "name": "excludeThirdPartyOat", + "type": "Microsoft.Common.CheckBox", + "label": "Exclude third-party OAT detections (productCode == 'tlc')", + "defaultValue": true, + "toolTip": "When checked, the DCR transform drops rows where productCode == 'tlc' (third-party linked sources). Uncheck to ingest everything." + } + ] + } + ], + "outputs": { + "workspace": "[basics('workspace')]", + "workspace-location": "[location()]", + "trendaiRegion": "[steps('trendConfig').trendaiRegion]", + "apikey": "[steps('trendConfig').apikey]", + "oatFilter": "[steps('trendConfig').oatFilter]", + "excludeThirdPartyOat": "[steps('trendConfig').excludeThirdPartyOat]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/oat/mainTemplate.json b/Solutions/TrendAI Vision One/templates/oat/mainTemplate.json new file mode 100644 index 00000000000..e57f31f251c --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/oat/mainTemplate.json @@ -0,0 +1,231 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "Trend Vision One - OAT (Observed Attack Techniques) Connector", + "description": "This solution installs the Trend Vision One OAT data connector to ingest MITRE ATT&CK mapped detections into Microsoft Sentinel.", + "author": { + "name": "Trend Micro" + }, + "support": { + "tier": "Partner", + "name": "Trend Micro", + "link": "https://www.trendmicro.com/support" + } + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is set up" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location of the workspace (same as workspace region)" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "US", + "allowedValues": ["UK", "US", "SG", "CA", "JP"], + "metadata": { + "description": "Trend Vision One region where your tenant is hosted" + } + }, + "apikey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Trend Vision One API token (without 'Bearer' prefix). Required to deploy the active poller. Leave empty to deploy only the connector definition + table + DCR and connect later via the Sentinel portal." + } + }, + "oatFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter expression for the OAT API. Example: (riskLevel eq 'high'). Leave empty for no filter." + } + }, + "excludeThirdPartyOat": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Exclude OAT detections from third-party linked sources (productCode == 'tlc'). Defaults to true." + } + } + }, + "variables": { + "baseUrl": "https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/oat/components" + }, + "resources": [ + { + "name": "sentinelSolution", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/sentinel-solution.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"} + } + } + }, + { + "name": "customTable", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'sentinelSolution')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/table.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"} + } + } + }, + { + "name": "dataCollectionEndpoint", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/dce.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace-location": {"value": "[parameters('workspace-location')]"} + } + } + }, + { + "name": "dataCollectionRule", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionEndpoint')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/dcr.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"}, + "dceName": {"value": "[reference('dataCollectionEndpoint').outputs.dceName.value]"}, + "tableName": {"value": "[reference('customTable').outputs.tableName.value]"}, + "excludeThirdPartyOat": {"value": "[parameters('excludeThirdPartyOat')]"} + } + } + }, + { + "name": "connectorDefinition", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'sentinelSolution')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionRule')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/connector-definition.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"} + } + } + }, + { + "name": "parserFunction", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/parser-function.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"} + } + } + }, + { + "name": "dataConnector", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "condition": "[not(empty(parameters('apikey')))]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'connectorDefinition')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionRule')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionEndpoint')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/data-connector.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"}, + "apikey": {"value": "[parameters('apikey')]"}, + "trendaiRegion": {"value": "[parameters('trendaiRegion')]"}, + "oatFilter": {"value": "[parameters('oatFilter')]"}, + "dceEndpoint": {"value": "[reference('dataCollectionEndpoint').outputs.dceEndpoint.value]"}, + "dcrImmutableId": {"value": "[reference('dataCollectionRule').outputs.dcrImmutableId.value]"}, + "streamName": {"value": "[reference('dataCollectionRule').outputs.streamName.value]"} + } + } + } + ], + "outputs": { + "workspaceName": { + "type": "string", + "value": "[parameters('workspace')]" + }, + "trendaiRegion": { + "type": "string", + "value": "[parameters('trendaiRegion')]" + }, + "tableName": { + "type": "string", + "value": "[reference('customTable').outputs.tableName.value]" + }, + "dceEndpoint": { + "type": "string", + "value": "[reference('dataCollectionEndpoint').outputs.dceEndpoint.value]" + }, + "dcrImmutableId": { + "type": "string", + "value": "[reference('dataCollectionRule').outputs.dcrImmutableId.value]" + }, + "parserFunctionName": { + "type": "string", + "value": "[reference('parserFunction').outputs.functionName.value]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/analytic-rule.json b/Solutions/TrendAI Vision One/templates/workbench/components/analytic-rule.json new file mode 100644 index 00000000000..1fc4092d9a5 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/analytic-rule.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Location of the workspace" + } + } + }, + "variables": { + "analyticRuleId": "[guid('workbench-analytic-rule', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('analyticRuleId'))]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This Query creates an incident based on Trend Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.", + "displayName": "Trend Vision One - Create Incident for Workbench Alerts", + "enabled": false, + "query": "TrendMicroWorkbench_Complete\n| extend Severity = case(severity_s == \"low\", \"Informational\",\n severity_s == \"medium\", \"Low\",\n severity_s == \"high\", \"Medium\",\n \"High\"\n )", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "tactics": [], + "techniques": [], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "UserAccountName_s", + "identifier": "Name" + }, + { + "columnName": "UserAccountNTDomain_s", + "identifier": "NTDomain" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "FileName_s", + "identifier": "Name" + }, + { + "columnName": "FileDirectory_s", + "identifier": "Directory" + } + ], + "entityType": "File" + }, + { + "fieldMappings": [ + { + "columnName": "ProcessCommandLine_s", + "identifier": "CommandLine" + } + ], + "entityType": "Process" + }, + { + "fieldMappings": [ + { + "columnName": "RegistryKey_s", + "identifier": "Key" + } + ], + "entityType": "RegistryKey" + }, + { + "fieldMappings": [ + { + "columnName": "RegistryValueName_s", + "identifier": "Name" + }, + { + "columnName": "RegistryValue_s", + "identifier": "Value" + } + ], + "entityType": "RegistryValue" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + }, + "customDetails": { + "Provider": "alertProvider_s", + "PriorityScore": "priorityScore_d", + "ImpactScopeSummary": "impactScope_Summary_s", + "WorkbenchID": "workbenchId_s", + "WorkbenchLink": "workbenchLink_s", + "WorkbenchName": "workbenchName_s", + "Severity": "severity_s", + "XDRCustomerID": "xdrCustomerID_g", + "CreatedAt": "createdTime_t" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "{{workbenchName_s}}", + "alertSeverityColumnName": "Severity", + "alertDescriptionFormat": "{{description_s}}" + }, + "incidentConfiguration": { + "createIncident": true, + "groupingConfiguration": { + "matchingMethod": "Selected", + "enabled": true, + "lookbackDuration": "PT5M", + "reopenClosedIncident": false, + "groupByCustomDetails": [ + "WorkbenchID" + ] + } + } + } + } + ], + "outputs": { + "analyticRuleId": { + "type": "string", + "value": "[variables('analyticRuleId')]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/connector-definition.json b/Solutions/TrendAI Vision One/templates/workbench/components/connector-definition.json new file mode 100644 index 00000000000..383a96380fe --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/connector-definition.json @@ -0,0 +1,190 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "US", + "allowedValues": ["UK", "US", "SG", "CA", "JP"], + "metadata": { + "description": "Trend Vision One region" + } + }, + "dcrImmutableId": { + "type": "string", + "metadata": { + "description": "DCR Immutable ID" + } + }, + "dceEndpoint": { + "type": "string", + "metadata": { + "description": "Data Collection Endpoint URL" + } + } + }, + "variables": { + "connectorId": "TrendMicro_XDR_Workbench", + "tableName": "TrendMicro_XDR_WORKBENCH_V2_CL", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'))]", + "location": "[parameters('location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "[variables('connectorId')]", + "title": "Trend Vision One - Workbench Alerts", + "publisher": "Trend Micro", + "logo": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik01LjI1MDEzIDkuNzM3MjdDNi4yMjk1NCAxMC43MzY3IDcuMTgzNzEgMTEuOTc0IDcuNDA1NTMgMTMuMjgwM0M3LjgwNDc2IDExLjA0MTIgMTAuODE3MiA3Ljk5MzM4IDEzLjA2NTcgNy42MDczMUMxMC44MzE4IDcuMjQ1MjkgNy43NjA0OSA0LjE3MjUxIDcuNDA1NyAxLjkyOTY5QzcuMDAzNDcgNC4xNDI2MiAzLjk3MDAzIDcuMjE3ODIgMS43NDUzNyA3LjYwNDAzQzMuMDQxOTIgNy44Mjc1OSA0LjI1NDcyIDguNzY0NjggNS4yNTAxMyA5LjczNzI3WiIgZmlsbD0iI0Q3MTkyMCIvPgo8cGF0aCBkPSJNMjMuMDgyMyAzLjMyNzY0QzIwLjc3MDcgMC41NjYwOTMgMTYuNDczMyAxLjQwOTQ5IDEzLjE1NCAyLjc1OTNDMTguNDIxOCAxLjA5NDcyIDIzLjI1MjQgMy4yODUwMiAyMC43MzE3IDkuNTQ2MTFDMTkuNDgzIDEyLjYyNDMgMTYuMzQyMSAxNS43NzI4IDEzLjMzMjIgMTcuNTUyNkMxMS43NDI4IDE4LjU4MDEgMTAuMDQyNyAxOS40NDU1IDguMTkwMDYgMTkuNzA0NkM1LjMzOTggMjAuMDk1NyAzLjYzMTY1IDE4LjYyNDIgNC4zNTY2MyAxNS42ODM3QzQuNTM5NDUgMTQuOTY1NyA0Ljg3MjI2IDE0LjI0MDggNS4yMDI2OCAxMy41MzU2QzQuNjU4NzIgMTIuMjQ0NiAzLjQ4ODM3IDEwLjkyMzkgMi4yMzIzOCAxMC41NTY5QzEuNTU1MzMgMTEuNTc1NiAxLjA2MjcyIDEyLjQ5NzcgMC41NjE0OTUgMTMuOTIzNUMtMC41NzI4MTIgMTYuOTg3OCAtMC4yMDIzMDIgMjEuNDg3MyAzLjY3MzY1IDIyLjQ2MDlDMTAuNzY2OCAyMy44NzQxIDIwLjM2MiAxNi4zMzQ2IDIzLjA5MzEgMTAuMDUxNUMyNC4yNjIgNy40MDM0NSAyNC4zNDU2IDQuOTU1ODggMjMuMDgyMyAzLjMyNzY0WiIgZmlsbD0iI0Q3MTkyMCIvPgo8L3N2Zz4K", + "descriptionMarkdown": "The Trend Vision One Workbench data connector provides the capability to ingest Workbench alerts into Microsoft Sentinel using the REST API. The connector provides visibility into security events and threats detected by Trend Vision One.", + "graphQueriesTableName": "[variables('tableName')]", + "dataTypes": [{ + "name": "[variables('tableName')]", + "lastDataReceivedQuery": "[concat(variables('tableName'), ' | summarize Time = max(TimeGenerated) | where isnotempty(Time)')]" + }], + "connectivityCriteria": [{ + "type": "HasDataConnectors" + }], + "graphQueries": [{ + "metricName": "Total data received", + "legend": "[variables('tableName')]", + "baseQuery": "[variables('tableName')]" + }], + "sampleQueries": [ + { + "description": "All Workbench Alerts", + "query": "[concat(variables('tableName'), ' | take 10')]" + }, + { + "description": "High and Critical Severity Alerts", + "query": "[concat(variables('tableName'), ' | where severity_s in (\"high\", \"critical\") | project TimeGenerated, workbenchId_s, workbenchName_s, severity_s, priorityScore_d')]" + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [{ + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + }] + }, + "instructionSteps": [ + { + "title": "1. Get API Token", + "description": "Obtain your Trend Vision One API token", + "instructions": [{ + "type": "InfoMessage", + "parameters": { + "text": "1. Log in to Trend Vision One Console\n2. Navigate to Administration > API Keys\n3. Generate a new API key with 'Workbench' or 'SIEM' role permissions\n4. Copy the token for the next step" + } + }] + }, + { + "title": "2. Connect to Trend Vision One", + "description": "Provide your API credentials", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Token (include 'Bearer ' prefix)", + "placeholder": "Bearer eyJ0eXAi...", + "type": "text", + "name": "apiKey" + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectButtonLabel": "Connect", + "disconnectButtonLabel": "Disconnect" + } + } + ] + }, + { + "title": "3. Verify Data Ingestion", + "description": "Check that data is flowing", + "instructions": [{ + "type": "InfoMessage", + "parameters": { + "text": "[concat('Run this query in Log Analytics (allow 5-10 minutes):\\n', variables('tableName'), ' | where TimeGenerated > ago(1h) | take 10')]" + } + }] + } + ] + }, + "dcrConfig": { + "streamName": "Custom-TrendMicro_XDR_WORKBENCH_V2_CL", + "dataCollectionEndpoint": "[parameters('dceEndpoint')]", + "dataCollectionRuleImmutableId": "[parameters('dcrImmutableId')]" + }, + "dataType": "[variables('tableName')]", + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKeyIdentifier": "apiKey" + }, + "request": { + "apiEndpoint": "[concat('https://', variables('apiHostnames')[parameters('trendaiRegion')], '/v3.0/workbench/alerts')]", + "rateLimitQPS": 1, + "queryWindowInMin": 5, + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "retryCount": 2, + "timeoutInSeconds": 60, + "startTimeAttributeName": "startDateTime", + "endTimeAttributeName": "endDateTime", + "headers": {}, + "queryParameters": {} + }, + "response": { + "eventsJsonPaths": ["$.items"], + "format": "json" + }, + "paging": { + "pagingType": "LinkHeader", + "linkHeaderTokenJsonPath": "$.nextLink" + } + } + } + ], + "outputs": { + "connectorId": { + "type": "string", + "value": "[variables('connectorId')]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/data-connector.json b/Solutions/TrendAI Vision One/templates/workbench/components/data-connector.json new file mode 100644 index 00000000000..ad4a3460b9b --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/data-connector.json @@ -0,0 +1,111 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string" + }, + "workspace-location": { + "type": "string" + }, + "apikey": { + "type": "securestring", + "metadata": { + "description": "Trend Vision One API token (without 'Bearer' prefix)." + } + }, + "trendaiRegion": { + "type": "string", + "allowedValues": [ "UK", "US", "SG", "CA", "JP" ], + "metadata": { + "description": "Trend Vision One region where the tenant is hosted." + } + }, + "workbenchFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter expression for the Workbench alerts API. Example: (severity ge 'high'). Leave empty for no filter." + } + }, + "dceEndpoint": { + "type": "string", + "metadata": { + "description": "Logs-ingestion endpoint URL of the Data Collection Endpoint." + } + }, + "dcrImmutableId": { + "type": "string", + "metadata": { + "description": "Immutable ID of the Data Collection Rule." + } + }, + "streamName": { + "type": "string", + "metadata": { + "description": "Stream name declared by the DCR (e.g. Custom-TrendMicro_XDR_WORKBENCH_V2_CL)." + } + } + }, + "variables": { + "connectorId": "TrendMicro_XDR_Workbench", + "apiHostnames": { + "UK": "api.uk.xdr.trendmicro.com", + "US": "api.xdr.trendmicro.com", + "SG": "api.sg.xdr.trendmicro.com", + "CA": "api.ca.xdr.trendmicro.com", + "JP": "api.jp.xdr.trendmicro.com" + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', variables('connectorId'), '-connection')]", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[variables('connectorId')]", + "dataType": "TrendMicro_XDR_WORKBENCH_V2_CL", + "dcrConfig": { + "streamName": "[parameters('streamName')]", + "dataCollectionEndpoint": "[parameters('dceEndpoint')]", + "dataCollectionRuleImmutableId": "[parameters('dcrImmutableId')]" + }, + "auth": { + "type": "APIKey", + "apiKeyName": "Authorization", + "apiKey": "[concat('Bearer ', parameters('apikey'))]" + }, + "request": { + "apiEndpoint": "[concat('https://', variables('apiHostnames')[parameters('trendaiRegion')], '/v3.0/workbench/alerts')]", + "rateLimitQPS": 1, + "queryWindowInMin": 5, + "httpMethod": "GET", + "queryTimeFormat": "yyyy-MM-dd'T'HH:mm:ss'Z'", + "startTimeAttributeName": "startDateTime", + "endTimeAttributeName": "endDateTime", + "headers": "[if(empty(parameters('workbenchFilter')), json('{}'), json(concat('{\"TMV1-Filter\": \"', parameters('workbenchFilter'), '\"}')))]", + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.items" + ], + "format": "json" + }, + "paging": { + "pagingType": "LinkHeader", + "linkHeaderTokenJsonPath": "$.nextLink" + } + } + } + ], + "outputs": { + "connectorId": { + "type": "string", + "value": "[variables('connectorId')]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/dce.json b/Solutions/TrendAI Vision One/templates/workbench/components/dce.json new file mode 100644 index 00000000000..1084517cf7b --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/dce.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources" + } + } + }, + "variables": { + "dceName": "TrendMicro-XDR-DCE" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dceName')]", + "location": "[parameters('location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + } + ], + "outputs": { + "dceId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName'))]" + }, + "dceName": { + "type": "string", + "value": "[variables('dceName')]" + }, + "dceEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionEndpoints', variables('dceName')), '2021-09-01-preview').logsIngestion.endpoint]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/dcr.json b/Solutions/TrendAI Vision One/templates/workbench/components/dcr.json new file mode 100644 index 00000000000..d6d64eecbb6 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/dcr.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources" + } + }, + "dceId": { + "type": "string", + "metadata": { + "description": "Data Collection Endpoint resource ID" + } + } + }, + "variables": { + "dcrName": "TrendMicro-XDR-Workbench-DCR", + "tableName": "TrendMicro_XDR_WORKBENCH_V2_CL", + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2021-09-01-preview", + "name": "[variables('dcrName')]", + "location": "[parameters('location')]", + "properties": { + "dataCollectionEndpointId": "[parameters('dceId')]", + "streamDeclarations": { + "Custom-TrendMicro_XDR_WORKBENCH_V2_CL": { + "columns": [ + {"name": "id", "type": "string"}, + {"name": "schemaVersion", "type": "string"}, + {"name": "investigationStatus", "type": "string"}, + {"name": "status", "type": "string"}, + {"name": "investigationResult", "type": "string"}, + {"name": "workbenchLink", "type": "string"}, + {"name": "alertProvider", "type": "string"}, + {"name": "modelId", "type": "string"}, + {"name": "model", "type": "string"}, + {"name": "modelType", "type": "string"}, + {"name": "score", "type": "int"}, + {"name": "severity", "type": "string"}, + {"name": "createdDateTime", "type": "datetime"}, + {"name": "updatedDateTime", "type": "datetime"}, + {"name": "incidentId", "type": "string"}, + {"name": "description", "type": "string"}, + {"name": "impactScope", "type": "dynamic"}, + {"name": "indicators", "type": "dynamic"}, + {"name": "matchedRules", "type": "dynamic"} + ] + } + }, + "destinations": { + "logAnalytics": [{ + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + }] + }, + "dataFlows": [{ + "streams": ["Custom-TrendMicro_XDR_WORKBENCH_V2_CL"], + "destinations": ["clv2ws1"], + "transformKql": "source | extend TimeGenerated = todatetime(createdDateTime) | extend SourceSystem = 'RestAPI' | extend Computer = '' | extend MG = '' | extend ManagementGroupName = '' | extend RawData = tostring(indicators) | extend workbenchId_s = tostring(id) | extend schemaVersion_s = tostring(schemaVersion) | extend investigationStatus_s = tostring(investigationStatus) | extend alertStatus_s = tostring(status) | extend investigationResult_s = tostring(investigationResult) | extend workbenchLink_s = tostring(workbenchLink) | extend alertProvider_s = tostring(alertProvider) | extend modelId_g = tostring(modelId) | extend modelId_s = tostring(modelId) | extend model_s = tostring(model) | extend workbenchName_s = tostring(model) | extend modelType_s = tostring(modelType) | extend priorityScore_d = todouble(score) | extend severity_s = tostring(severity) | extend createdTime_t = todatetime(createdDateTime) | extend updatedTime_t = todatetime(updatedDateTime) | extend alertTriggerTimestamp_t = todatetime(createdDateTime) | extend workbenchCompleteTimestamp_t = todatetime(updatedDateTime) | extend incidentId_s = tostring(incidentId) | extend description_s = tostring(description) | extend desktopCount_d = todouble(impactScope.desktopCount) | extend serverCount_d = todouble(impactScope.serverCount) | extend accountCount_d = todouble(impactScope.accountCount) | extend emailAddressCount_d = todouble(impactScope.emailAddressCount) | extend containerCount_d = todouble(impactScope.containerCount) | extend cloudIdentityCount_d = todouble(impactScope.cloudIdentityCount) | extend cloudWorkloadCount_d = todouble(impactScope.cloudWorkloadCount) | extend indicators_dynamic = indicators | extend indicators_s = tostring(indicators) | extend impactScope_s = tostring(impactScope) | extend impactScope_Summary_s = tostring(impactScope) | extend entities = impactScope.entities | extend matchedRules_dynamic = matchedRules | extend matchedRules_s = tostring(matchedRules) | extend xdrCustomerID_g = '' | extend FileName_s = '' | extend FileHashValue_s = '' | extend DomainName_s = '' | extend FileDirectory_s = '' | extend IPAddress = '' | extend URL_s = '' | extend HostHostName_s = '' | extend ProcessCommandLine_s = '' | extend RegistryKey_s = '' | extend RegistryValue_s = '' | extend RegistryValueName_s = '' | extend UserAccountNTDomain_s = '' | extend UserAccountName_s = '' | extend MailboxPrimaryAddress_s = '' | extend MalwareName_s = '' | extend indicators = indicators_dynamic | extend matchedRules = matchedRules_dynamic | project-away id, schemaVersion, investigationStatus, status, investigationResult, workbenchLink, alertProvider, modelId, model, modelType, score, severity, createdDateTime, updatedDateTime, incidentId, description, impactScope, indicators_dynamic, matchedRules_dynamic", + "outputStream": "Custom-TrendMicro_XDR_WORKBENCH_V2_CL" + }] + } + } + ], + "outputs": { + "dcrId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName'))]" + }, + "dcrName": { + "type": "string", + "value": "[variables('dcrName')]" + }, + "dcrImmutableId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionRules', variables('dcrName')), '2021-09-01-preview').immutableId]" + }, + "streamName": { + "type": "string", + "value": "Custom-TrendMicro_XDR_WORKBENCH_V2_CL" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/parser-function.json b/Solutions/TrendAI Vision One/templates/workbench/components/parser-function.json new file mode 100644 index 00000000000..60742321032 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/parser-function.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Deploys the TrendMicroWorkbench_Complete parser function to Log Analytics workspace" + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Workspace Azure region" + } + } + }, + "variables": { + "functionName": "TrendMicroWorkbench_Complete", + "functionAlias": "TrendMicroWorkbench_Complete", + "category": "TrendMicro", + "functionQuery": "union isfuzzy=true\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // LEGACY DATA: Use AS-IS (already in correct format)\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n (TrendMicro_XDR_WORKBENCH_CL),\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // V2 CCF DATA: Transform to match legacy format using working parser logic\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n (TrendMicro_XDR_WORKBENCH_V2_CL\n // Auto-detect format: use dynamic column if available, otherwise parse string column\n | extend indicators_array = iff(isnull(indicators), parse_json(indicators_s), indicators)\n | extend impactScope_parsed = iff(isnull(entities), parse_json(impactScope_s), dynamic(null))\n | extend entities_array = iff(isnull(entities), impactScope_parsed.entities, entities)\n | extend matchedRules_array = iff(isnull(matchedRules), parse_json(matchedRules_s), matchedRules)\n // Extract count fields from impactScope (only for old data)\n | extend desktopCount_extracted = iff(isnull(entities), toint(impactScope_parsed.desktopCount), toint(desktopCount_d))\n | extend serverCount_extracted = iff(isnull(entities), toint(impactScope_parsed.serverCount), toint(serverCount_d))\n | extend accountCount_extracted = iff(isnull(entities), toint(impactScope_parsed.accountCount), toint(accountCount_d))\n | extend emailAddressCount_extracted = iff(isnull(entities), toint(impactScope_parsed.emailAddressCount), toint(emailAddressCount_d))\n // Step 1: Expand and extract indicators\n | mv-expand indicator = indicators_array\n | extend ind_type = tostring(indicator.type)\n | extend ind_value = tostring(indicator.value)\n | extend ind_field = tostring(indicator.field)\n // Aggregate IOCs by workbenchId\n | summarize\n ProcessCommandLine_s = maxif(ind_value, ind_type == \"command_line\"),\n FileName_s = maxif(ind_value, ind_type == \"filename\"),\n FileHashValue_s = maxif(ind_value, ind_type in (\"file_sha1\", \"file_sha256\", \"md5\")),\n DomainName_s = maxif(ind_value, ind_type == \"domain\"),\n FileDirectory_s = maxif(ind_value, ind_type == \"fullpath\"),\n IPAddress_extracted = maxif(ind_value, ind_type == \"ip\"),\n URL_s = maxif(ind_value, ind_type == \"url\"),\n RegistryKey_s = maxif(ind_value, ind_type == \"registry_key\"),\n RegistryValue_s = maxif(ind_value, ind_type == \"registry_value_data\"),\n RegistryValueName_s = maxif(ind_value, ind_type == \"registry_value\"),\n MalwareName_s = maxif(ind_value, ind_type == \"detection_name\"),\n entities_array = any(entities_array),\n // Preserve extracted counts\n desktopCount_extracted = any(desktopCount_extracted),\n serverCount_extracted = any(serverCount_extracted),\n accountCount_extracted = any(accountCount_extracted),\n emailAddressCount_extracted = any(emailAddressCount_extracted),\n // Preserve all columns\n TimeGenerated = any(TimeGenerated),\n SourceSystem = any(SourceSystem),\n MG = any(MG),\n ManagementGroupName = any(ManagementGroupName),\n Computer = any(Computer),\n RawData = any(RawData),\n schemaVersion_s = any(schemaVersion_s),\n investigationStatus_s = any(investigationStatus_s),\n alertStatus_s = any(alertStatus_s),\n investigationResult_s = any(investigationResult_s),\n workbenchLink_s = any(workbenchLink_s),\n alertProvider_s = any(alertProvider_s),\n modelId_g = any(modelId_g),\n modelId_s = any(modelId_s),\n model_s = any(model_s),\n workbenchName_s = any(workbenchName_s),\n modelType_s = any(modelType_s),\n priorityScore_d = any(priorityScore_d),\n severity_s = any(severity_s),\n createdTime_t = any(createdTime_t),\n updatedTime_t = any(updatedTime_t),\n alertTriggerTimestamp_t = any(alertTriggerTimestamp_t),\n workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t),\n incidentId_s = any(incidentId_s),\n description_s = any(description_s),\n desktopCount_d = any(desktopCount_d),\n serverCount_d = any(serverCount_d),\n accountCount_d = any(accountCount_d),\n emailAddressCount_d = any(emailAddressCount_d),\n indicators_s = any(indicators_s),\n impactScope_s = any(impactScope_s),\n impactScope_Summary_s = any(impactScope_Summary_s),\n matchedRules_s = any(matchedRules_s),\n xdrCustomerID_g = any(xdrCustomerID_g),\n TenantId = any(TenantId),\n Type = any(Type),\n _ResourceId = any(_ResourceId)\n by workbenchId_s\n // Step 2: Expand and extract entities\n | mv-expand entity = entities_array\n | extend ent_type = tostring(entity.entityType)\n | extend ent_value = entity.entityValue\n | extend ent_value_str = tostring(entity.entityValue)\n | extend ent_value_name = tostring(entity.entityValue.name)\n // Aggregate entities by workbenchId\n | summarize\n HostHostName_s = maxif(ent_value_name, ent_type == \"host\"),\n UserAccountFull = maxif(ent_value_str, ent_type == \"account\" and ent_value_str contains \"\\\\\"),\n MailboxPrimaryAddress_s = maxif(ent_value_str, ent_type == \"emailAddress\"),\n // Keep IOCs from previous step\n ProcessCommandLine_s = any(ProcessCommandLine_s),\n FileName_s = any(FileName_s),\n FileHashValue_s = any(FileHashValue_s),\n DomainName_s = any(DomainName_s),\n FileDirectory_s = any(FileDirectory_s),\n IPAddress_extracted = any(IPAddress_extracted),\n URL_s = any(URL_s),\n RegistryKey_s = any(RegistryKey_s),\n RegistryValue_s = any(RegistryValue_s),\n RegistryValueName_s = any(RegistryValueName_s),\n MalwareName_s = any(MalwareName_s),\n // Keep extracted counts\n desktopCount_extracted = any(desktopCount_extracted),\n serverCount_extracted = any(serverCount_extracted),\n accountCount_extracted = any(accountCount_extracted),\n emailAddressCount_extracted = any(emailAddressCount_extracted),\n // Keep all other columns\n TimeGenerated = any(TimeGenerated),\n SourceSystem = any(SourceSystem),\n MG = any(MG),\n ManagementGroupName = any(ManagementGroupName),\n Computer = any(Computer),\n RawData = any(RawData),\n schemaVersion_s = any(schemaVersion_s),\n investigationStatus_s = any(investigationStatus_s),\n alertStatus_s = any(alertStatus_s),\n investigationResult_s = any(investigationResult_s),\n workbenchLink_s = any(workbenchLink_s),\n alertProvider_s = any(alertProvider_s),\n modelId_g = any(modelId_g),\n modelId_s = any(modelId_s),\n model_s = any(model_s),\n workbenchName_s = any(workbenchName_s),\n modelType_s = any(modelType_s),\n priorityScore_d = any(priorityScore_d),\n severity_s = any(severity_s),\n createdTime_t = any(createdTime_t),\n updatedTime_t = any(updatedTime_t),\n alertTriggerTimestamp_t = any(alertTriggerTimestamp_t),\n workbenchCompleteTimestamp_t = any(workbenchCompleteTimestamp_t),\n incidentId_s = any(incidentId_s),\n description_s = any(description_s),\n desktopCount_d = any(desktopCount_d),\n serverCount_d = any(serverCount_d),\n accountCount_d = any(accountCount_d),\n emailAddressCount_d = any(emailAddressCount_d),\n indicators_s = any(indicators_s),\n impactScope_s = any(impactScope_s),\n impactScope_Summary_s = any(impactScope_Summary_s),\n matchedRules_s = any(matchedRules_s),\n xdrCustomerID_g = any(xdrCustomerID_g),\n TenantId = any(TenantId),\n Type = any(Type),\n _ResourceId = any(_ResourceId)\n by workbenchId_s\n // Step 3: Parse domain\\username and apply defaults\n | extend UserAccountNTDomain_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, \"\\\\\")[0], \"[]\")\n | extend UserAccountName_s = iff(isnotempty(UserAccountFull), split(UserAccountFull, \"\\\\\")[1], \"[]\")\n // Apply backward-compatible empty value defaults\n | extend\n FileName_s = coalesce(FileName_s, \"[]\"),\n FileHashValue_s = coalesce(FileHashValue_s, \"[]\"),\n DomainName_s = coalesce(DomainName_s, \"[]\"),\n FileDirectory_s = coalesce(FileDirectory_s, \"[]\"),\n IPAddress = coalesce(IPAddress_extracted, \"[]\"),\n URL_s = coalesce(URL_s, \"[]\"),\n HostHostName_s = coalesce(HostHostName_s, \"[]\"),\n ProcessCommandLine_s = coalesce(ProcessCommandLine_s, \"[]\"),\n RegistryKey_s = coalesce(RegistryKey_s, \"[]\"),\n RegistryValue_s = coalesce(RegistryValue_s, \"[]\"),\n RegistryValueName_s = coalesce(RegistryValueName_s, \"[]\"),\n MailboxPrimaryAddress_s = coalesce(MailboxPrimaryAddress_s, \"[]\"),\n MalwareName_s = coalesce(MalwareName_s, \"[]\"),\n // Apply count defaults\n desktopCount_d = coalesce(desktopCount_extracted, 0),\n serverCount_d = coalesce(serverCount_extracted, 0),\n accountCount_d = coalesce(accountCount_extracted, 0),\n emailAddressCount_d = coalesce(emailAddressCount_extracted, 0)\n | project // Final projection with exact backward-compatible schema\n TimeGenerated,\n SourceSystem,\n MG,\n ManagementGroupName,\n Computer,\n RawData,\n FileName_s,\n FileHashValue_s,\n DomainName_s,\n FileDirectory_s,\n IPAddress,\n URL_s,\n HostHostName_s,\n ProcessCommandLine_s,\n RegistryKey_s,\n RegistryValue_s,\n RegistryValueName_s,\n UserAccountNTDomain_s,\n UserAccountName_s,\n alertProvider_s,\n alertTriggerTimestamp_t,\n createdTime_t,\n description_s,\n impactScope_s,\n impactScope_Summary_s,\n indicators_s,\n investigationStatus_s,\n matchedRules_s,\n model_s,\n modelId_g,\n modelId_s,\n priorityScore_d,\n severity_s,\n updatedTime_t,\n workbenchCompleteTimestamp_t,\n workbenchId_s,\n workbenchLink_s,\n workbenchName_s,\n xdrCustomerID_g,\n MailboxPrimaryAddress_s,\n MalwareName_s,\n schemaVersion_s,\n alertStatus_s,\n investigationResult_s,\n modelType_s,\n incidentId_s,\n desktopCount_d,\n serverCount_d,\n accountCount_d,\n emailAddressCount_d,\n Type,\n TenantId,\n _ResourceId\n )\n" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[concat(parameters('workspace'), '/', variables('functionName'))]", + "location": "[parameters('workspace-location')]", + "properties": { + "displayName": "[variables('functionName')]", + "category": "[variables('category')]", + "functionAlias": "[variables('functionAlias')]", + "query": "[variables('functionQuery')]", + "version": 2 + } + } + ], + "outputs": { + "functionName": { + "type": "string", + "value": "[variables('functionName')]" + }, + "message": { + "type": "string", + "value": "\u2705 Parser function deployed! Usage: TrendMicroWorkbench_Complete() | where severity_s == 'critical'" + } + } +} \ No newline at end of file diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/sentinel-solution.json b/Solutions/TrendAI Vision One/templates/workbench/components/sentinel-solution.json new file mode 100644 index 00000000000..649ddd00d51 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/sentinel-solution.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources" + } + } + }, + "variables": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/Workspaces', parameters('workspace'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[concat('SecurityInsights(', parameters('workspace'), ')')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[variables('workspaceResourceId')]" + }, + "plan": { + "name": "[concat('SecurityInsights(', parameters('workspace'), ')')]", + "product": "OMSGallery/SecurityInsights", + "publisher": "Microsoft", + "promotionCode": "" + } + } + ], + "outputs": { + "solutionId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationsManagement/solutions', concat('SecurityInsights(', parameters('workspace'), ')'))]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/table.json b/Solutions/TrendAI Vision One/templates/workbench/components/table.json new file mode 100644 index 00000000000..c99177dc1a0 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/table.json @@ -0,0 +1,103 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace name" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources" + } + } + }, + "variables": { + "tableName": "TrendMicro_XDR_WORKBENCH_V2_CL" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[concat(parameters('workspace'), '/', variables('tableName'))]", + "location": "[parameters('location')]", + "properties": { + "schema": { + "name": "[variables('tableName')]", + "columns": [ + {"name": "TimeGenerated", "type": "datetime"}, + {"name": "SourceSystem", "type": "string"}, + {"name": "MG", "type": "string"}, + {"name": "ManagementGroupName", "type": "string"}, + {"name": "Computer", "type": "string"}, + {"name": "RawData", "type": "string"}, + {"name": "workbenchId_s", "type": "string"}, + {"name": "schemaVersion_s", "type": "string"}, + {"name": "investigationStatus_s", "type": "string"}, + {"name": "alertStatus_s", "type": "string"}, + {"name": "investigationResult_s", "type": "string"}, + {"name": "workbenchLink_s", "type": "string"}, + {"name": "alertProvider_s", "type": "string"}, + {"name": "modelId_g", "type": "string"}, + {"name": "modelId_s", "type": "string"}, + {"name": "model_s", "type": "string"}, + {"name": "workbenchName_s", "type": "string"}, + {"name": "modelType_s", "type": "string"}, + {"name": "priorityScore_d", "type": "real"}, + {"name": "severity_s", "type": "string"}, + {"name": "createdTime_t", "type": "datetime"}, + {"name": "updatedTime_t", "type": "datetime"}, + {"name": "alertTriggerTimestamp_t", "type": "datetime"}, + {"name": "workbenchCompleteTimestamp_t", "type": "datetime"}, + {"name": "incidentId_s", "type": "string"}, + {"name": "description_s", "type": "string"}, + {"name": "desktopCount_d", "type": "real"}, + {"name": "serverCount_d", "type": "real"}, + {"name": "accountCount_d", "type": "real"}, + {"name": "emailAddressCount_d", "type": "real"}, + {"name": "containerCount_d", "type": "real"}, + {"name": "cloudIdentityCount_d", "type": "real"}, + {"name": "cloudWorkloadCount_d", "type": "real"}, + {"name": "indicators_s", "type": "string"}, + {"name": "indicators", "type": "dynamic"}, + {"name": "impactScope_s", "type": "string"}, + {"name": "impactScope_Summary_s", "type": "string"}, + {"name": "entities", "type": "dynamic"}, + {"name": "matchedRules_s", "type": "string"}, + {"name": "matchedRules", "type": "dynamic"}, + {"name": "xdrCustomerID_g", "type": "string"}, + {"name": "FileName_s", "type": "string"}, + {"name": "FileHashValue_s", "type": "string"}, + {"name": "DomainName_s", "type": "string"}, + {"name": "FileDirectory_s", "type": "string"}, + {"name": "IPAddress", "type": "string"}, + {"name": "URL_s", "type": "string"}, + {"name": "HostHostName_s", "type": "string"}, + {"name": "ProcessCommandLine_s", "type": "string"}, + {"name": "RegistryKey_s", "type": "string"}, + {"name": "RegistryValue_s", "type": "string"}, + {"name": "RegistryValueName_s", "type": "string"}, + {"name": "UserAccountNTDomain_s", "type": "string"}, + {"name": "UserAccountName_s", "type": "string"}, + {"name": "MailboxPrimaryAddress_s", "type": "string"}, + {"name": "MalwareName_s", "type": "string"} + ] + } + } + } + ], + "outputs": { + "tableName": { + "type": "string", + "value": "[variables('tableName')]" + }, + "tableId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('tableName'))]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/components/workbook.json b/Solutions/TrendAI Vision One/templates/workbench/components/workbook.json new file mode 100644 index 00000000000..b92f11f1953 --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/components/workbook.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Location of the workspace" + } + } + }, + "variables": { + "workbookId": "[guid('workbench-workbook', parameters('workspace'))]", + "workbookName": "TrendVisionOneWorkbenchOverview" + }, + "resources": [ + { + "type": "Microsoft.Insights/workbooks", + "name": "[variables('workbookId')]", + "location": "[parameters('workspace-location')]", + "apiVersion": "2023-06-01", + "kind": "shared", + "properties": { + "displayName": "[variables('workbookName')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Trend Vision One - Workbench Alerts\\n---\\n[Trend Micro Success Portal](https://success.trendmicro.com)\\n\\nIf you have any feedback, please send to \"},\"name\":\"text - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(7d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 7 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 30 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by bin(TimeGenerated,1d), model_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Detection Models in Last 30 Days\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| summarize Alerts = count() by severity_s\\n| render piechart\",\"size\":0,\"title\":\"Alerts by Severity\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 4\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete\\n| where isnotempty(HostHostName_s) and HostHostName_s != '[]'\\n| summarize Alerts = count() by HostHostName_s\\n| top 10 by Alerts desc\",\"size\":0,\"title\":\"Top 10 Affected Hosts\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 5\"}],\"styleSettings\":{},\"fromTemplateId\":\"sentinel-TrendVisionOneWorkbench\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}", + "version": "1.0", + "sourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.OperationalInsights/workspaces/', parameters('workspace'))]", + "category": "sentinel" + } + } + ], + "outputs": { + "workbookId": { + "type": "string", + "value": "[variables('workbookId')]" + }, + "workbookName": { + "type": "string", + "value": "[variables('workbookName')]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/createUiDefinition.json b/Solutions/TrendAI Vision One/templates/workbench/createUiDefinition.json new file mode 100644 index 00000000000..b351573fefc --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/createUiDefinition.json @@ -0,0 +1,152 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "isWizard": false, + "basics": { + "description": "**Trend Vision One - Workbench Alerts Data Connector**\n\n This solution installs a data connector to ingest Workbench security alerts from Trend Vision One into Microsoft Sentinel.\n\n **Data Connector:** 1\n\n **Parser Function:** 1\n\n [Learn more about Trend Vision One](https://www.trendmicro.com/vision-one)", + "subscription": { + "constraints": { + "validations": [] + }, + "resourceProviders": [ + "Microsoft.OperationalInsights", + "Microsoft.SecurityInsights", + "Microsoft.Insights", + "Microsoft.OperationsManagement" + ] + }, + "resourceGroup": { + "constraints": {}, + "allowExisting": true + }, + "location": { + "label": "Location", + "toolTip": "Location for all resources", + "resourceTypes": [ + "Microsoft.OperationalInsights/workspaces" + ] + } + } + }, + "basics": [ + { + "name": "getLAWorkspace", + "type": "Microsoft.Solutions.ArmApiControl", + "toolTip": "This filters by workspaces that exist in the Resource Group selected", + "condition": "[greater(length(resourceGroup().name),0)]", + "request": { + "method": "GET", + "path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]" + } + }, + { + "name": "workspace", + "type": "Microsoft.Common.DropDown", + "label": "Workspace", + "placeholder": "Select a workspace", + "toolTip": "Select the Microsoft Sentinel workspace where you want to install the solution", + "constraints": { + "allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + }, + "visible": true + } + ], + "steps": [ + { + "name": "dataconnectors", + "label": "Data Connector Configuration", + "elements": [ + { + "name": "dataconnectors-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the Trend Vision One Workbench data connector. After deployment, you'll need to configure the connector with your Trend Vision One API credentials." + } + }, + { + "name": "trendaiRegion", + "type": "Microsoft.Common.DropDown", + "label": "Trend Vision One Region", + "placeholder": "Select your Trend Vision One region", + "toolTip": "Select the region where your Trend Vision One tenant is hosted", + "constraints": { + "allowedValues": [ + { + "label": "United States", + "value": "US" + }, + { + "label": "United Kingdom", + "value": "UK" + }, + { + "label": "Singapore", + "value": "SG" + }, + { + "label": "Canada", + "value": "CA" + }, + { + "label": "Japan", + "value": "JP" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "dataconnectors-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Provide your Trend Vision One API token below to enable the live poller at deploy time. If you leave it blank, the connector definition still deploys and you can connect later from the Sentinel portal.", + "link": { + "label": "Learn more about getting API tokens", + "uri": "https://docs.trendmicro.com/en-us/enterprise/trend-vision-one/administrator/api-access-management.aspx" + } + } + }, + { + "name": "apikey", + "type": "Microsoft.Common.PasswordBox", + "label": { + "password": "Trend Vision One API Token", + "confirmPassword": "Confirm API Token" + }, + "toolTip": "Bearer token (without the 'Bearer' prefix). Leave blank to skip the live poller; the rest of the connector still deploys.", + "constraints": { + "required": false, + "regex": "", + "validationMessage": "" + }, + "options": { + "hideConfirmation": true + } + }, + { + "name": "workbenchFilter", + "type": "Microsoft.Common.TextBox", + "label": "Optional TMV1-Filter", + "defaultValue": "", + "toolTip": "Optional TMV1-Filter expression sent on every Workbench API call. Example: (severity ge 'high'). Leave empty for no filter.", + "constraints": { + "required": false + } + } + ] + } + ], + "outputs": { + "workspace-location": "[location()]", + "workspace": "[basics('workspace')]", + "trendaiRegion": "[steps('dataconnectors').trendaiRegion]", + "apikey": "[steps('dataconnectors').apikey]", + "workbenchFilter": "[steps('dataconnectors').workbenchFilter]" + } + } +} diff --git a/Solutions/TrendAI Vision One/templates/workbench/mainTemplate.json b/Solutions/TrendAI Vision One/templates/workbench/mainTemplate.json new file mode 100644 index 00000000000..d73c02417dc --- /dev/null +++ b/Solutions/TrendAI Vision One/templates/workbench/mainTemplate.json @@ -0,0 +1,370 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "Trend Vision One - Workbench Alerts Connector", + "description": "This solution installs the Trend Vision One Workbench data connector to ingest security alerts into Microsoft Sentinel. After installing the solution, configure and enable this data connector by following the guidance in the Configuration section below.", + "author": { + "name": "Trend Micro" + }, + "support": { + "tier": "Partner", + "name": "Trend Micro", + "link": "https://www.trendmicro.com/support" + } + }, + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is set up" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location of the workspace (same as workspace region)" + } + }, + "trendaiRegion": { + "type": "string", + "defaultValue": "US", + "allowedValues": ["UK", "US", "SG", "CA", "JP"], + "metadata": { + "description": "Trend Vision One region where your tenant is hosted" + } + }, + "apikey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Trend Vision One API token (without 'Bearer' prefix). Required to deploy the active poller. Leave empty to deploy only the connector definition + table + DCR + parser, and attach credentials later via the Sentinel portal." + } + }, + "workbenchFilter": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional TMV1-Filter expression for the Workbench alerts API. Example: (severity ge 'high'). Leave empty for no filter." + } + } + }, + "variables": { + "baseUrl": "https://raw.githubusercontent.com/trendmicro/trendai-sentinel-ccf-data-connector/main/templates/workbench/components" + }, + "resources": [ + { + "name": "sentinelSolution", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/sentinel-solution.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": { + "value": "[parameters('workspace')]" + }, + "location": { + "value": "[parameters('workspace-location')]" + } + } + } + }, + { + "name": "customTable", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'sentinelSolution')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/table.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": { + "value": "[parameters('workspace')]" + }, + "location": { + "value": "[parameters('workspace-location')]" + } + } + } + }, + { + "name": "dataCollectionEndpoint", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/dce.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "location": { + "value": "[parameters('workspace-location')]" + } + } + } + }, + { + "name": "dataCollectionRule", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionEndpoint')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/dcr.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": { + "value": "[parameters('workspace')]" + }, + "location": { + "value": "[parameters('workspace-location')]" + }, + "dceId": { + "value": "[reference('dataCollectionEndpoint').outputs.dceId.value]" + } + } + } + }, + { + "name": "connectorDefinition", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'sentinelSolution')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionRule')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/connector-definition.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": { + "value": "[parameters('workspace')]" + }, + "location": { + "value": "[parameters('workspace-location')]" + }, + "trendaiRegion": { + "value": "[parameters('trendaiRegion')]" + }, + "dcrImmutableId": { + "value": "[reference('dataCollectionRule').outputs.dcrImmutableId.value]" + }, + "dceEndpoint": { + "value": "[reference('dataCollectionEndpoint').outputs.dceEndpoint.value]" + } + } + } + }, + { + "name": "parserFunction", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/parser-function.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": { + "value": "[parameters('workspace')]" + }, + "workspace-location": { + "value": "[parameters('workspace-location')]" + } + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules", + "name": "[concat(parameters('workspace'), '/Microsoft.SecurityInsights/', guid('workbench-analytic-rule', parameters('workspace')))]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]", + "[resourceId('Microsoft.Resources/deployments', 'parserFunction')]" + ], + "properties": { + "description": "This Query creates an incident based on Trend Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.", + "displayName": "Trend Vision One - Create Incident for Workbench Alerts", + "enabled": false, + "query": "TrendMicroWorkbench_Complete()\n| extend Severity = case(severity_s == \"low\", \"Informational\",\n severity_s == \"medium\", \"Low\",\n severity_s == \"high\", \"Medium\",\n \"High\"\n )\n| extend \n UserAccountName_s = todynamic(column_ifexists(\"UserAccountName_s\", \"[]\")),\n UserAccountNTDomain_s = todynamic(column_ifexists(\"UserAccountNTDomain_s\", \"[]\")),\n FileName_s = todynamic(column_ifexists(\"FileName_s\", \"[]\")),\n FileDirectory_s = todynamic(column_ifexists(\"FileDirectory_s\", \"[]\")),\n ProcessCommandLine_s = todynamic(column_ifexists(\"ProcessCommandLine_s\", \"[]\")),\n RegistryKey_s = todynamic(column_ifexists(\"RegistryKey_s\", \"[]\")),\n RegistryValue_s = todynamic(column_ifexists(\"RegistryValue_s\", \"[]\")),\n RegistryValueName_s = todynamic(column_ifexists(\"RegistryValueName_s\", \"[]\"))", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "tactics": [], + "techniques": [], + "entityMappings": [ + { + "fieldMappings": [ + {"columnName": "UserAccountName_s", "identifier": "Name"}, + {"columnName": "UserAccountNTDomain_s", "identifier": "NTDomain"} + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + {"columnName": "FileName_s", "identifier": "Name"}, + {"columnName": "FileDirectory_s", "identifier": "Directory"} + ], + "entityType": "File" + }, + { + "fieldMappings": [ + {"columnName": "ProcessCommandLine_s", "identifier": "CommandLine"} + ], + "entityType": "Process" + }, + { + "fieldMappings": [ + {"columnName": "RegistryKey_s", "identifier": "Key"} + ], + "entityType": "RegistryKey" + }, + { + "fieldMappings": [ + {"columnName": "RegistryValueName_s", "identifier": "Name"}, + {"columnName": "RegistryValue_s", "identifier": "Value"} + ], + "entityType": "RegistryValue" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + }, + "customDetails": { + "Provider": "alertProvider_s", + "PriorityScore": "priorityScore_d", + "ImpactScopeSummary": "impactScope_Summary_s", + "WorkbenchID": "workbenchId_s", + "WorkbenchLink": "workbenchLink_s", + "WorkbenchName": "workbenchName_s", + "Severity": "severity_s", + "XDRCustomerID": "xdrCustomerID_g", + "CreatedAt": "createdTime_t" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "{{workbenchName_s}}", + "alertSeverityColumnName": "Severity", + "alertDescriptionFormat": "{{description_s}}" + }, + "incidentConfiguration": { + "createIncident": true, + "groupingConfiguration": { + "matchingMethod": "Selected", + "enabled": true, + "lookbackDuration": "PT5M", + "reopenClosedIncident": false, + "groupByCustomDetails": ["WorkbenchID"] + } + } + } + }, + { + "type": "Microsoft.Insights/workbooks", + "name": "[guid('workbench-workbook', parameters('workspace'))]", + "location": "[parameters('workspace-location')]", + "apiVersion": "2023-06-01", + "kind": "shared", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'customTable')]" + ], + "properties": { + "displayName": "TrendVisionOneWorkbenchOverview", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Trend Vision One - Workbench Alerts\\n---\\n[Trend Micro Success Portal](https://success.trendmicro.com)\\n\\nIf you have any feedback, please send to \"},\"name\":\"text - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete()\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(7d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 7 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete()\\n| summarize Alerts = count() by bin(TimeGenerated,1d), severity_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Workbench Alerts Last 30 days\",\"timeContext\":{\"durationMs\":2592000000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete()\\n| summarize Alerts = count() by bin(TimeGenerated,1d), model_s\\n| where TimeGenerated >= ago(30d)\\n| render columnchart kind=stacked\",\"size\":0,\"title\":\"Detection Models in Last 30 Days\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete()\\n| summarize Alerts = count() by severity_s\\n| render piechart\",\"size\":0,\"title\":\"Alerts by Severity\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"medium\",\"label\":\"Medium\",\"color\":\"orange\"},{\"seriesName\":\"high\",\"label\":\"High\",\"color\":\"redBright\"},{\"seriesName\":\"low\",\"label\":\"Low\",\"color\":\"yellow\"},{\"seriesName\":\"critical\",\"label\":\"Critical\",\"color\":\"redDark\"}]}},\"name\":\"query - 4\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"TrendMicroWorkbench_Complete()\\n| where isnotempty(HostHostName_s) and HostHostName_s != '[]'\\n| summarize Alerts = count() by HostHostName_s\\n| top 10 by Alerts desc\",\"size\":0,\"title\":\"Top 10 Affected Hosts\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 5\"}],\"styleSettings\":{},\"fromTemplateId\":\"sentinel-TrendVisionOneWorkbench\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}", + "version": "1.0", + "sourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.OperationalInsights/workspaces/', parameters('workspace'))]", + "category": "sentinel" + } + }, + { + "name": "dataConnector", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "condition": "[not(empty(parameters('apikey')))]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'connectorDefinition')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionRule')]", + "[resourceId('Microsoft.Resources/deployments', 'dataCollectionEndpoint')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[concat(variables('baseUrl'), '/data-connector.json')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "workspace": {"value": "[parameters('workspace')]"}, + "workspace-location": {"value": "[parameters('workspace-location')]"}, + "apikey": {"value": "[parameters('apikey')]"}, + "trendaiRegion": {"value": "[parameters('trendaiRegion')]"}, + "workbenchFilter": {"value": "[parameters('workbenchFilter')]"}, + "dceEndpoint": {"value": "[reference('dataCollectionEndpoint').outputs.dceEndpoint.value]"}, + "dcrImmutableId": {"value": "[reference('dataCollectionRule').outputs.dcrImmutableId.value]"}, + "streamName": {"value": "[reference('dataCollectionRule').outputs.streamName.value]"} + } + } + } + ], + "outputs": { + "workspace": { + "type": "string", + "value": "[parameters('workspace')]" + }, + "tableName": { + "type": "string", + "value": "[reference('customTable').outputs.tableName.value]" + }, + "dcrImmutableId": { + "type": "string", + "value": "[reference('dataCollectionRule').outputs.dcrImmutableId.value]" + }, + "dceEndpoint": { + "type": "string", + "value": "[reference('dataCollectionEndpoint').outputs.dceEndpoint.value]" + }, + "parserFunctionName": { + "type": "string", + "value": "[reference('parserFunction').outputs.functionName.value]" + }, + "analyticRuleId": { + "type": "string", + "value": "[guid('workbench-analytic-rule', parameters('workspace'))]" + }, + "workbookId": { + "type": "string", + "value": "[guid('workbench-workbook', parameters('workspace'))]" + }, + "message": { + "type": "string", + "value": "✅ Deployment complete! Deployed: Data connector, Parser function, Analytic rule (disabled), and Workbook. Next steps: 1) Connect: Sentinel → Data connectors → 'Trend Vision One - Workbench Alerts' 2) Enable analytic rule: Sentinel → Analytics → 'Trend Vision One - Create Incident for Workbench Alerts' 3) View dashboard: Sentinel → Workbooks → 'TrendVisionOneWorkbenchOverview'" + } + } +}