Rubrik Plugin for Threat Exchange
Rubrik Plugin for Threat Exchange
This document explains how to configure the v1.0.0 Rubrik plugin with the Threat Exchange module of the Cloud Exchange platform. This plugin supports sharing the threat IoCs of type MD5 and SHA256 to the Rubrik’s Threat Hunt page, and can perform a Start Threat Hunt action.
Prerequisites
To complete the plugin configuration, you’ll need:
- A Netskope tenant (or multiple, for example, production and development/test instances) that is already configured in Cloud Exchange.
- A Netskope Cloud Exchange tenant with the Threat Exchange module already configured.
- Connectivity to the following host: https://rubrik-tme.my.rubrik.com/
CE Version Compatibility
Netskope CE: v4.2.0, and v5.0.1
Rubrik Plugin Support
The plugin supports pushing SHA256, and MD5 to Rubrik. The plugin also supports performing the Start Threat Hunt action on the Shared IoCs.
Fetched indicator types | Not Supported |
Shared indicator types | SHA256, MD5 |
API Details
List of APIs used
Use Case | Method | Endpoint | API Scope |
---|---|---|---|
Get auth token | POST | /api/client_token | None |
Get objectFids from Rubrik platform | POST | /api/graphql | Threat Hunt (Read) |
Get the clusters present on Rubrik | POST | /api/graphql | Threat Hunt
(Read) |
Start Threat Hunt on Rubrik | POST | /api/graphql | Threat Hunt (Read) |
Get Auth Token
API Endpoint: /api/client_token
Method: POST
Headers
Key | Value |
---|---|
User-Agent | netskope-ce-5.0.1-cte-rubrik-v1.0.0 |
Payload
Parameter | Value |
---|---|
client_id | <Client ID> |
client_secret | <Client Secret> |
Sample API Response
{ "access_token": "", "expires_in": 43200, "Client_id" : “” }
API for Start Threat Hunt Action
Get ObjectFids from Rubrik
API Endpoint: /api/graphql
Method: POST
Headers
Key | Value |
User-Agent | netskope-ce-5.0.1-cte-rubrik-v1.0.0 |
Authorization | Bearer <Bearer Token> |
Content-Type | application/json |
Payload
GraphQL Query | Variables |
---|---|
query SnappableQuery($first: Int, $after: String, $typeFilter: [HierarchyObjectTypeEnum!], $filter: [Filter!], $sortBy: HierarchySortByField, $sortOrder: SortOrder) { inventoryRoot { descendantConnection(first: $first, after: $after, typeFilter: $typeFilter, filter: $filter, sortBy: $sortBy, sortOrder: $sortOrder) { edges { cursor node { id ... on WindowsFileset { isPassThrough __typename } ... on ShareFileset { isPassThrough __typename } ... on LinuxFileset { isPassThrough __typename } ... on O365Onedrive { userPrincipalName __typename } ...EffectiveSlaColumnFragment ...HierarchyObjectClusterColumnFragment ...HierarchyObjectLocationColumnFragment ...HierarchyObjectNameColumnFragment ...HierarchyObjectTypeFragment ... on AzureNativeVirtualMachine { region isAdeEnabled resourceGroup { subscription { name __typename } __typename } effectiveSlaDomain { ...ArchivalSpecFragment __typename } __typename } ... on AzureNativeManagedDisk { region isAdeEnabled resourceGroup { subscription { name __typename } __typename } effectiveSlaDomain { ...ArchivalSpecFragment __typename } __typename } ... on CloudDirectNasExport { exportPath __typename } __typename } __typename } pageInfo { endCursor hasNextPage hasPreviousPage __typename } __typename } __typename } } fragment EffectiveSlaColumnFragment on HierarchyObject { id effectiveSlaDomain { ...EffectiveSlaDomainFragment ... on GlobalSlaReply { description __typename } __typename } ... on CdmHierarchyObject { pendingSla { ...SLADomainFragment __typename } __typename } __typename } fragment EffectiveSlaDomainFragment on SlaDomain { id name ... on GlobalSlaReply { isRetentionLockedSla retentionLockMode __typename } ... on ClusterSlaDomain { fid cluster { id name __typename } isRetentionLockedSla retentionLockMode __typename } __typename } fragment SLADomainFragment on SlaDomain { id name ... on ClusterSlaDomain { fid cluster { id name __typename } __typename } __typename } fragment HierarchyObjectClusterColumnFragment on HierarchyObject { ...CdmClusterLabelFragment ... on CloudDirectHierarchyObject { cluster { id name __typename } __typename } __typename } fragment CdmClusterLabelFragment on CdmHierarchyObject { cluster { id name version __typename } primaryClusterLocation { id __typename } __typename } fragment HierarchyObjectLocationColumnFragment on HierarchyObject { logicalPath { name objectType __typename } physicalPath { name objectType __typename } __typename } fragment HierarchyObjectNameColumnFragment on HierarchyObject { name __typename } fragment HierarchyObjectTypeFragment on HierarchyObject { objectType __typename } fragment ArchivalSpecFragment on GlobalSlaReply { archivalSpec { storageSetting { targetType __typename } __typename } archivalSpecs { storageSetting { targetType __typename } __typename } __typename } |
{ "first": 1, "filter": [ { "texts": [ "false" ], "field": "IS_GHOST" }, { "texts": [ “” ], "field": "CLUSTER_ID" } ], "sortBy": "NAME", "sortOrder": "ASC", "typeFilter": [ "LinuxFileset", "ShareFileset", "VmwareVirtualMachine", "WindowsFileset", "HypervVirtualMachine", "NutanixVirtualMachine", "NAS_FILESET" ], "after":"Y3Vyc29yOmludDow" } |
Sample API Response
{ "data": { "inventoryRoot": { "descendantConnection": { "edges": [ { "cursor": "Y3Vyc29yOmludDox", "node": { "id": "", "effectiveSlaDomain": { "id": "", "name": "MGMT-12H-30D-1Y-AWS-USW1", "isRetentionLockedSla": false, "retentionLockMode": "NO_MODE", "__typename": "GlobalSlaReply", "description": "Upgraded from Cluster_A" }, "pendingSla": null, "__typename": "NasFileset", "cluster": { "id": "", "name": "Cluster_A", "version": "8.1.3-p11-25483", "__typename": "Cluster" }, "primaryClusterLocation": { "id": "", "__typename": "DataLocation" }, "logicalPath": [ { "name": "/volume1/ISO: **", "objectType": "FilesetTemplate", "__typename": "PathNode" }, { "name": "/volume1/ISO", "objectType": "NasShare", "__typename": "PathNode" }, { "name": "synology.rubrik.us", "objectType": "NasSystem", "__typename": "PathNode" } ], "physicalPath": [ { "name": "/volume1/ISO: **", "objectType": "FilesetTemplate", "__typename": "PathNode" }, { "name": "/volume1/ISO", "objectType": "NasShare", "__typename": "PathNode" }, { "name": "synology.rubrik.us", "objectType": "NasSystem", "__typename": "PathNode" } ], "name": "/volume1/ISO: **", "objectType": "NAS_FILESET" }, "__typename": "HierarchyObjectEdge" } ], "pageInfo": { "endCursor": "Y3Vyc29yOmludDox", "hasNextPage": true, "hasPreviousPage": true, "__typename": "PageInfo" }, "__typename": "HierarchyObjectConnection" }, "__typename": "InventoryRoot" } } }
Get Clusters Present on Rubrik
API Endpoint: /api/graphql
Method: POST
Headers
Key | Value |
---|---|
User-Agent | netskope-ce-5.0.1-cte-rubrik-v1.0.0 |
Authorization | Bearer <Bearer Token> |
Content-Type | application/json |
Payload
GraphQL Query | Variables |
---|---|
query ClusterPickerQuery($first: Int, $after: String, $filter: ClusterFilterInput, $sortBy: ClusterSortByEnum, $sortOrder: SortOrder) { clusterConnection(filter: $filter, sortBy: $sortBy, sortOrder: $sortOrder, first: $first, after: $after) { edges { cursor node { id status ...ClusterIconNameFragment ...ClusterVersionColumnFragment ...ClusterTypeColumnFragment ...ClusterCapacityColumnFragment ...ClusterProtectedCountColumnFragment ...ClusterGeoLocationColumnFragment ...ClusterNameColumnFragment __typename } __typename } pageInfo { startCursor endCursor hasNextPage hasPreviousPage __typename } __typename } } fragment ClusterIconNameFragment on Cluster { id name status pauseStatus state { clusterRemovalState __typename } defaultAddress passesConnectivityCheck connectivityLastUpdated ...ClusterNodeConnectionFragment globalManagerConnectivityStatus { urls { url isReachable __typename } __typename } systemStatus ccprovisionInfo { jobStatus jobType progress vendor __typename } __typename } fragment ClusterNodeConnectionFragment on Cluster { clusterNodeConnection { nodes { id status ipAddress __typename } __typename } __typename } fragment ClusterVersionColumnFragment on Cluster { version eosDate eosStatus __typename } fragment ClusterTypeColumnFragment on Cluster { name productType type clusterNodeConnection { nodes { id __typename } __typename } __typename } fragment ClusterCapacityColumnFragment on Cluster { metric { usedCapacity availableCapacity totalCapacity __typename } __typename } fragment ClusterProtectedCountColumnFragment on Cluster { productType noSqlWorkloadCount ...ClusterProtectedSnappablesFragment __typename } fragment ClusterProtectedSnappablesFragment on Cluster { protectedSnappables: snappableConnection(filter: {protectionStatus: Protected}) { count __typename } __typename } fragment ClusterGeoLocationColumnFragment on Cluster { geoLocation { address __typename } __typename } fragment ClusterNameColumnFragment on Cluster { name __typename } |
{ "sortBy": "ClusterName", "sortOrder": "ASC", "filter": { "type": [], "name": [ "" ] }, "first": 1 } |
Sample API Response
{ "data": { "clusterConnection": { "edges": [ { "cursor": "Y3Vyc29yOmludDow", "node": { "id": "40fdb2a5-3591-40ee-a37a-50bce5240d62", "status": "Connected", "name": "Cluster_A", "pauseStatus": "NOT_PAUSED", "state": { "clusterRemovalState": "REGISTERED", "__typename": "clusterState" }, "defaultAddress": "cluster-a-rr.rubrik.us", "passesConnectivityCheck": true, "connectivityLastUpdated": "2024-08-05T10:16:10.000Z", "clusterNodeConnection": { "nodes": [ { "id": "RVMHM223S002373", "status": "OK", "ipAddress": "10.8.107.107", "__typename": "ClusterNode" }, { "id": "RVMHM223S002379", "status": "OK", "ipAddress": "10.8.107.106", "__typename": "ClusterNode" }, { "id": "RVMHM223S002714", "status": "OK", "ipAddress": "10.8.107.104", "__typename": "ClusterNode" }, { "id": "RVMHM223S002718", "status": "OK", "ipAddress": "10.8.107.105", "__typename": "ClusterNode" } ], "__typename": "ClusterNodeConnection" }, "__typename": "Cluster", "globalManagerConnectivityStatus": { "urls": [ { "url": "https://rubrik-tme.my.rubrik.com", "isReachable": true, "__typename": "GlobalManagerUrl" } ], "__typename": "GlobalManagerConnectivity" }, "systemStatus": "OK", "ccprovisionInfo": { "jobStatus": "INITIALIZING", "jobType": "ADD_NODE", "progress": 0, "vendor": "VENDOR_UNKNOWN", "__typename": "CcprovisionInfo" }, "version": "8.1.3-p11-25483", "eosDate": "2024-07-25", "eosStatus": "EOS_STATUS_UNSUPPORTED", "productType": "CDM", "type": "OnPrem", "metric": { "usedCapacity": 7113709735936, "availableCapacity": 54306599845888, "totalCapacity": 61420309581824, "__typename": "ClusterMetric" }, "noSqlWorkloadCount": 0, "protectedSnappables": { "count": 148, "__typename": "SnappableConnection" }, "geoLocation": { "address": "Santa Clara, CA, USA", "__typename": "GeoLocation" } }, "__typename": "ClusterEdge" } ], "pageInfo": { "startCursor": "Y3Vyc29yOmludDow", "endCursor": "Y3Vyc29yOmludDow", "hasNextPage": true, "hasPreviousPage": false, "__typename": "PageInfo" }, "__typename": "ClusterConnection" } } }
Start Threat Hunt on Rubrik
API Endpoint: /api/graphql
Method: POST
Headers
Key | Value |
---|---|
User-Agent | netskope-ce-5.0.1-cte-rubrik-v1.0.0 |
Authorization | Bearer <Bearer Token> |
Content-Type | application/json |
Payload
GraphQL Query | Variables |
---|---|
mutation StartThreatHuntMutation($input: StartThreatHuntInput!) { startThreatHunt(input: $input) { huntId isSyncSuccessful __typename } } |
{ "input": { "clusterUuid": "40fdb2a5-3591-40ee-a37a-50bce5240d62", "indicatorsOfCompromise": [ { "iocKind": "IOC_HASH", "iocValue": "sha256:a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e" }, { "iocKind": "IOC_HASH", "iocValue": "sha256:a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146f" } ], "objectFids": [ “” ], "fileScanCriteria": { "fileSizeLimits": { "maximumSizeInBytes": 1024, "minimumSizeInBytes": 5 }, "pathFilter": { "includes": [ "*.acm", "*.ax", "*.cpl", "*.dll", "*.drv", "*.efi", "*.exe", "*.mui", "*.ocx", "*.scr", "*.sys", "*.tsp" ], "excludes": [], "exceptions": [] } }, "maxMatchesPerSnapshot": 1, "name": "Sample threat hunt", "shouldTrustFilesystemTimeInfo": true, "snapshotScanLimit": { "maxSnapshotsPerObject": 1 } } } |
Sample API Response
{ "data": { "startThreatHunt": { "huntId": "892caaf9-90d3-5c87-8297-5862e972a032", "isSyncSuccessful": true, "__typename": "StartThreatHuntReply" } } }
Performance Matrix
Here is the performance reading conducted by sharing 100K indicators to Rubrik on a Large CE Stack with these specifications.
Stack details | Size: Large RAM: 32 GB CPU: 16 Cores |
Indicators fetched from Rubrik | NA |
Indicators shared with Rubrik | ~26K per minute |
User Agent
netskope-ce-5.0.1-cte-rubrik-v1.0-0
Workflow
- Get your Client ID and Client Secret.
- Configure the Rubrik plugin.
- Configure a Threat Exchange Business Rule.
- Configure Threat Exchange Sharing.
- Validate the Rubrik plugin.
Click play to watch a video:
Get your Configuration Parameters
Follow the steps in this document to generate the Client ID and Client Secret:
https://docs.rubrik.com/en-us/saas/saas/adding_a_service_account.html?hl=adding%2Cservice%2Caccount
Configure the Rubrik Plugin
- Log in to Cloud Exchange and go to Settings > Plugins.
- Search for and select the CTE Rubrik plugin box.
- Enter the Basic Information:
- Configuration Name: Plugin configuration name
- Sync Interval: Interval to fetch data from this plugin source.
- Aging Criteria: Expire indicators after a specific time.
- Override Reputation: Set value to override reputation of indicators received from this configuration. Leave empty to keep default.
- Enable SSL Validation: Enable SSL Certificate validation.
- Use System Proxy: Use system proxy configured in Settings.
- Click Next.
- Enter the Configuration Parameters:
- Base URL: Base URL of Rubrik instance, like https://rubrik01.rubrikdemo.com.
- Client ID: Client ID generated from the Rubrik platform. To obtain the Client ID, a Service Account JSON needs to be generated. In Rubrik, go to Apps > Settings > Users and Access to generate it.
- Client Secret: Client Secret generated from the Rubrik platform. To obtain the Client Secret, a Service Account JSON needs to be generated. In Rubrik, go to Apps > Settings > Users and Access to generate it.
- Click Save.
Configure a Business Rule for the Rubrik Plugin
A Business Rule is used to filter out the indicators that are to be shared. In order to share IoCs with Rubrik, create a business rule using these steps:
- Go to Threat Exchange > Business Rules and click Create New Rule.
- Add the Rule name and select the fields through which you want to filter the IoCs. When finished, click Save.
Add Sharing for the Rubrik Plugin
To configure the Sharing, follow these steps:
- Go to Threat Exchange > Sharing and click Add Sharing Configuration.
- Select a Source configuration (Source from which you want to share data to Rubrik), a Business Rule, and a Destination.
- Select the Target value, and enter these values:
- Threat Hunt Name: Enter the name of the Threat Hunt. A Threat Hunt with this name will be initiated on Rubrik.
- Cluster Name: Rubrik Cluster for which you want to initiate Threat Hunt.
- Max File Size to Scan (in KB): Maximum file size in KB to scan. Default is 1024 KB. Maximum supported size is 15000000 KB and minimum supported size is 1 KB.
- Min File Size to Scan (in KB): Minimum file size in KB to scan. Default is 5 KB. Maximum supported size is 15000000 KB and minimum supported size is 1 KB.
- Max IOC Matches (Per Snapshot): Maximum IOC matches per snapshot. Default is 1. Maximum supported value is 1000 and minimum supported value is 1.
- Include Files: Files to include in Threat Hunt.
- Exclude Files: Files to exclude from Threat Hunt.
- Do not Exclude Files: File which should not be excluded from Threat Hunt.
- Click Save.
Validate the Rubrik Plugin
Pull is not supported.
Validate the Push
Shared IoCs to Rubrik can be verified from logs available on the Logging page of Cloud Exchange.
IoCs shared on Rubrik can be verified at Apps > Data Threat Analytics > Threat Hunt. Click on the Threat Hunt that you created.
Click on the Parameters tab to view the shared IoCs.
Troubleshooting
Unable to configure the Rubrik Plugin
If you are unable to configure the Rubrik Plugin, then it could be due to one of the reasons mentioned-below:
- Proper permission is not provided to the credentials.
- Provided incorrect credentials.
To solve the issues mentioned above, follow these steps:
- Check the logs of the plugin in Cloud Exchange.
- Make sure that provided credentials have proper permissions.
- Make sure that correct credentials are provided while configuring the plugin.
Unable to push data to Rubrik
If you are unable to share the IoCs to the Rubrik Plugin, then it could be due to one of these reasons:
- Invalid value of MD5, and SHA256 provided.
- If the shared data has type other than MD5, or SHA256.
To solve the issues mentioned above, follow these steps:
- Check the logs of the plugin in Cloud Exchange.
- Make sure that the MD5, and SHA256 that needs to be shared are valid.
- Make sure that the IoCs are of type MD5, or SHA256.