DSPM
Remediate your data security risks. Integrate with Prisma Cloud DSPM to fetch your data security risks and remediate them with OOTB playbooks.
Network Security · DSPM
Details
| ID | DSPM |
|---|---|
| Provider | Palo Alto Networks |
| Category | Network Security |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
README
Overview
The Prisma Cloud DSPM(Data Security Posture Management) integration enhances the management and remediation of DSPM risks. The integration provides users with actionable data, insights and a seamless workflow for addressing potential security threats.
Use Cases
- Remediation of DSPM out-of-the-box risks based on automated playbooks.
- Close or update risks by interacting with DSPM API using a dedicated list of building blocks.
- Distribute DSPM risks to other systems.
Prerequisites
- An active Prisma Cloud DSPM account
- Slack V3 Pack
- AWS-S3 Pack
- Core REST APIs pack
- Atlassian Jira v3 Pack
- Google Cloud Storage Pack ( Optional )
- Azure Storage Container Pack ( Optional )
Configure Cortex XSOAR on Prisma Cloud DSPM
- Log in to you Prisma Cloud DSPM platform.
- Navigate to Settings > Workflow > XSOAR.
- Click Connect to create and configure a new XSOAR integration.
- XSOAR link - Add the XSOAR API URL.
- Notified On - Select the Risks option.
- Severity Threshold - Set the severity threshold to receive notifications for assets that fall under that severity.
- Filter By Tags - Notifications will be sent for assets that match any of the selected tags.
- Advanced - Add required headers Authorization and x-xdr-auth-id
Configure Prisma Cloud DSPM on Cortex XSOAR
- Navigate to Settings & Info > Settings > Integrations > Instances.
- Search for Prisma Cloud DSPM.
-
Click Add instance to create and configure a new integration instance.
Parameter Description Required DSPM server URL The tenant URL of the Prisma Cloud DSPM True DSPM API Key API key to use for the connection. True Trust any certificate (not secure) False Use system proxy settings False Fetch incidents False - Click Test to validate the URLs, token, and connection.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
dspm-list-risk-findings
Retrieves risk findings matching the input criteria.
Base Command
dspm-list-risk-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| rule_name_in | A comma-separated list of rule names. | Optional |
| rule_name_equal | The exact rule name. | Optional |
| dspm_tag_key_in | A comma-separated list of DSPM tag keys. | Optional |
| dspm_tag_key_equal | Exact DSPM tag key. | Optional |
| dspm_tag_value_in | A comma-separated list of DSPM tag values. | Optional |
| dspm_tag_value_equal | The exact DSPM tag value. | Optional |
| projectId_in | A comma-separated list of project IDs. | Optional |
| projectId_equal | The exact project ID. | Optional |
| cloud_provider_in | A comma-separated list of cloud providers. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. Default is AWS. | Optional |
| cloud_provider_equal | The exact cloud provider. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| affects_in | A comma-separated list of affects. Possible values are: SECURITY, COMPLIANCE, GOVERNANCE, SECURITY_AND_COMPLIANCE, SECURITY_AND_GOVERNANCE, COMPLIANCE_AND_GOVERNANCE, SECURITY_AND_COMPLIANCE_AND_GOVERNANCE. | Optional |
| affects_equal | The exact effect. Possible values are: SECURITY, COMPLIANCE, GOVERNANCE, SECURITY_AND_COMPLIANCE, COMPLIANCE_AND_GOVERNANCE, SECURITY_AND_GOVERNANCE, SECURITY_AND_COMPLIANCE_AND_GOVERNANCE. | Optional |
| status_in | A comma-separated list of statuses. Possible values are: OPEN, CLOSED, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Optional |
| status_equal | The exact status. Possible values are: OPEN, CLOSED, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Optional |
| sort | The sort order. | Optional |
| limit | The maximum number of risk findings to retrieve. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.RiskFinding.asset | Unknown | The asset details associated with the risk finding. |
| DSPM.RiskFinding.cloudEnvironment | String | The cloud environment (public or private) associated with the risk finding. |
| DSPM.RiskFinding.cloudProvider | String | The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). |
| DSPM.RiskFinding.complianceStandards | Unknown | The compliance standards relevant to the risk finding. |
| DSPM.RiskFinding.firstDiscovered | Date | The date the risk finding was first discovered. |
| DSPM.RiskFinding.id | String | The unique ID of the risk finding. |
| DSPM.RiskFinding.projectId | String | The project ID where the asset resides. |
| DSPM.RiskFinding.ruleName | String | The rule name associated with the risk finding. |
| DSPM.RiskFinding.severity | String | The severity of the risk finding (e.g., Low, Medium, High). |
| DSPM.RiskFinding.status | String | The current status of the risk finding (e.g., Open, Closed). |
Command example
#### Context Example
```json
{
"DSPM": {
"RiskFinding": [
{
"id": "00000000-0000-4f99-0000-616843b6b19e",
"ruleName": "Empty storage asset",
"severity": "LOW",
"asset": {},
"status": "OPEN",
"projectId": "********",
"cloudProvider": "AWS",
"cloudEnvironment": "UNKNOWN",
"firstDiscovered": "2024-09-27T11:55:39.059125Z",
"complianceStandards": {}
}
]
}
}
Human Readable Output
Results
Asset Cloud Environment Cloud Provider Compliance Standards First Discovered ID Project ID Rule Name Severity Status {} UNKNOWN AWS {} 2024-09-27T11:55:39.059125Z 00000000-0000-4f99-0000-616843b6b19e **** Empty storage asset LOW OPEN
dspm-get-risk-finding-by-id
Retrieves the details of a risk for the provided risk ID.
Base Command
dspm-get-risk-finding-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| finding_id | ID of the risk for which to retrieve details. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.RiskFinding.asset | Unknown | The asset details associated with the risk finding. |
| DSPM.RiskFinding.cloudEnvironment | String | The cloud environment (public or private) associated with the risk finding. |
| DSPM.RiskFinding.cloudProvider | String | The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). |
| DSPM.RiskFinding.complianceStandards | Unknown | The compliance standards relevant to the risk finding. |
| DSPM.RiskFinding.firstDiscovered | Date | The date the risk finding was first discovered. |
| DSPM.RiskFinding.id | String | The unique ID of the risk finding. |
| DSPM.RiskFinding.projectId | String | The project ID where the asset resides. |
| DSPM.RiskFinding.ruleName | String | The rule name associated with the risk finding. |
| DSPM.RiskFinding.severity | String | The severity of the risk finding (e.g., Low, Medium, High). |
| DSPM.RiskFinding.status | String | The current status of the risk finding (e.g., Open, Closed). |
Command example
!dspm-get-risk-finding-by-id finding_id="00000000-0000-4f99-0000-616843b6b19e"
Context Example
{
"DSPM": {
"RiskFinding": {
"id": "00000000-0000-4f99-0000-616843b6b19e",
"ruleName": "Empty storage asset",
"severity": "LOW",
"asset": {},
"status": "OPEN",
"projectId": "********",
"cloudProvider": "AWS",
"cloudEnvironment": "UNKNOWN",
"firstDiscovered": "2024-09-27T11:55:39.059125Z",
"complianceStandards": {}
}
}
}
Human Readable Output
Results
Asset Cloud Environment Cloud Provider Compliance Standards First Discovered ID Project ID Rule Name Severity Status {} UNKNOWN AWS {} 2024-09-27T11:55:39.059125Z 00000000-0000-4f99-0000-616843b6b19e **** Empty storage asset LOW OPEN
dspm-list-assets
Retrieves a list of assets for the company.
Base Command
dspm-list-assets
Input
| Argument Name | Description | Required |
|---|---|---|
| region_in | A comma-separated list of regions. | Optional |
| region_equal | The exact region. | Optional |
| cloud_provider_in | A comma-separated list of cloud providers. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| cloud_provider_equal | The exact cloud provider. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| service_type_in | A comma-separated list of service types. | Optional |
| service_type_equal | The exact service type. | Optional |
| lifecycle_in | A comma-separated list of life cycles. Possible values are: RUNNING, STOPPED, DELETED. | Optional |
| lifecycle_equal | The exact lifecycle. Possible values are: RUNNING, STOPPED, DELETED. | Optional |
| sort | The sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. | Optional |
| limit | The maximum number of assets to retrieve. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.Asset.dataTypes | Unknown | Data types associated with the asset. |
| DSPM.Asset.dataTypeGroups | Unknown | Data type groups associated with the asset. |
| DSPM.Asset.assetDigTags | Unknown | Dig tags associated with the asset. |
| DSPM.Asset.cloudEnvironment | String | The cloud environment in which the asset exists. |
| DSPM.Asset.cloudProvider | String | The cloud provider for the asset. |
| DSPM.Asset.encrypted | Boolean | Indicates if the asset is encrypted. |
| DSPM.Asset.id | String | The unique identifier of the asset. |
| DSPM.Asset.lifecycle | String | Lifecycle status of the asset. |
| DSPM.Asset.name | String | The name of the asset. |
| DSPM.Asset.openAlertsCount | Number | The count of open alerts for the asset. |
| DSPM.Asset.openRisksCount | Number | The count of open risks for the asset. |
| DSPM.Asset.openToWorld | Boolean | Indicates if the asset is open to the world. |
| DSPM.Asset.projectId | String | The ID of the project associated with the asset. |
| DSPM.Asset.projectName | String | The name of the project associated with the asset. |
| DSPM.Asset.serviceType | String | The type of service associated with the asset. |
| DSPM.Asset.tags | Unknown | Tags related to the asset. |
Command example
!dspm-list-assets cloudProviderEqual=AWS serviceTypeEqual=S3
Context Example
{
"DSPM": {
"Assets": [{
"projectId": "************",
"projectName": "************",
"name": "dymmy-ci0jq3kgvjnccdfp-us-east-1",
"cloudProvider": "AWS",
"cloudEnvironment": "TESTING",
"serviceType": "S3",
"dataTypeGroups": [],
"dataTypes": [],
"lifecycle": "RUNNING",
"openRisksCount": 0,
"openAlertsCount": 0,
"encrypted": true,
"openToWorld": false,
"tags": {},
"assetDigTags": [],
"id": "arn:aws:s3:::dymmy-ci0jq3kgvjnccdfp-us-east-1"
}]
}
}
Human Readable Output
Results
Asset Dig Tags Cloud Environment Cloud Provider Encrypted ID Lifecycle Name Open Alerts Count Open Risks Count Open To World Project ID Project Name Service Type Tags Data Type Groups Data Types TESTING AWS true arn:aws:s3:::dymmy-ci0jq3kgvjnccdfp-us-east-1 RUNNING dymmy-ci0jq3kgvjnccdfp-us-east-1 0 0 false **** **** S3
dspm-get-asset-details
Retrieves details for the specified asset ID.
Base Command
dspm-get-asset-details
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_id | ID of the asset for which to retrieve details. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.AssetDetails.assetDigTags | Unknown | The dig tags associated with the asset. |
| DSPM.AssetDetails.cloudEnvironment | String | The cloud environment in which the asset exists. |
| DSPM.AssetDetails.cloudProvider | String | The cloud provider for the asset (e.g., AWS, Azure, GCP). |
| DSPM.AssetDetails.dataTypeGroups | Unknown | Groups of data types associated with the asset. |
| DSPM.AssetDetails.dataTypes | Unknown | The data types related to the asset. |
| DSPM.AssetDetails.encrypted | Boolean | Indicates if the asset is encrypted. |
| DSPM.AssetDetails.id | String | The unique identifier of the asset. |
| DSPM.AssetDetails.lifecycle | String | The lifecycle status of the asset. |
| DSPM.AssetDetails.name | String | The name of the asset. |
| DSPM.AssetDetails.openAlertsCount | Number | The count of open alerts for the asset. |
| DSPM.AssetDetails.openRisksCount | Number | The count of open risks for the asset. |
| DSPM.AssetDetails.openToWorld | Boolean | Indicates if the asset is open to the world. |
| DSPM.AssetDetails.projectId | String | The ID of the project associated with the asset. |
| DSPM.AssetDetails.projectName | String | The name of the project associated with the asset. |
| DSPM.AssetDetails.serviceType | String | The type of service associated with the asset. |
| DSPM.AssetDetails.tags | Unknown | Tags related to the asset. |
Command example
!dspm-get-asset-details asset_id="arn:aws:s3:::dummyS3-cifp-us-east-1"
Context Example
{
"DSPM": {
"AssetDetails": {
"assetDigTags": [],
"cloudEnvironment": "TESTING",
"cloudProvider": "AWS",
"dataTypeGroups": [],
"dataTypes": [],
"encrypted": true,
"id": "arn:aws:s3:::dummyS3-cifp-us-east-1",
"lifecycle": "RUNNING",
"name": "dymmy-ci0jq3kgvjnccdfp-us-east-1",
"openAlertsCount": 0,
"openRisksCount": 0,
"openToWorld": false,
"projectId": "************",
"projectName": "************",
"serviceType": "S3",
"tags": {}
}
}
}
Human Readable Output
Results
assetDigTags cloudEnvironment cloudProvider dataTypeGroups dataTypes encrypted id lifecycle name openAlertsCount openRisksCount openToWorld projectId projectName serviceType tags TESTING AWS true arn:aws:s3:::dummyS3-cifp-us-east-1 RUNNING dymmy-ci0jq3kgvjnccdfp-us-east-1 0 0 false **** **** S3
dspm-get-asset-files-by-id
Retrieves file details for the specified asset ID.
Base Command
dspm-get-asset-files-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_id | ID of the asset for which to retrieve file details. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.AssetFiles.filename | String | Asset file name. |
| DSPM.AssetFiles.path | String | Asset file path. |
| DSPM.AssetFiles.type | String | Asset file type. |
| DSPM.AssetFiles.size | String | Asset file size. |
| DSPM.AssetFiles.openToWorld | Boolean | Whether the asset is open to world. |
| DSPM.AssetFiles.isDeleted | Boolean | Whether the asset is deleted. |
| DSPM.AssetFiles.isMalicious | Boolean | Whether the asset is malicious. |
| DSPM.AssetFiles.dataTypes.name | String | Asset file data types name. |
| DSPM.AssetFiles.dataTypes.label | String | Asset file data types label. |
| DSPM.AssetFiles.dataTypes.count | Number | Asset file data types count. |
| DSPM.AssetFiles.dataTypes.valueDetails.masked_value | String | Asset file data types value detail masked value. |
| DSPM.AssetFiles.dataTypes.valueDetails.line | Number | Asset file data types value detail line. |
| DSPM.AssetFiles.labels | String | Asset file labels. |
| DSPM.AssetFiles.isDbDump | Boolean | Asset file is a database dump. |
Command example
!dspm-get-asset-files-by-id asset_id="arn:aws:s3:::dummyS3-cifp-us-east-1"
Context Example
{
"files": [
{
"filename": "268d4e2d-03f2-4044-b82d-8855b2e77f8d.csv",
"path": "268d4e2d-03f2-4044-b82d-8855b2e77f8d.csv",
"type": "Data Format",
"size": "17081",
"openToWorld": true,
"isDeleted": false,
"isMalicious": false,
"dataTypes": [
{
"name": "IP Address",
"label": "Sensitive",
"count": 100,
"valueDetails": [
{
"masked_value": "20.163.*.*",
"line": 3
},
{
"masked_value": "38.229.*.*",
"line": 4
},
{
"masked_value": "45.136.*.*",
"line": 5
}
]
},
{
"name": "Internal IP Address",
"label": "Sensitive",
"count": 100,
"valueDetails": [
{
"masked_value": "10.0.*.*",
"line": 2
},
{
"masked_value": "10.0.*.*",
"line": 8
},
{
"masked_value": "10.0.*.*",
"line": 14
}
]
}
],
"labels": [
"Sensitive"
],
"isDbDump": false
},
{
"filename": "data security test cases.pdf",
"path": "data security test cases.pdf",
"type": "Document",
"size": "73286",
"openToWorld": true,
"isDeleted": false,
"isMalicious": false,
"dataTypes": [
{
"name": "Street Address",
"label": "Sensitive",
"count": 1,
"valueDetails": [
{
"masked_value": "3** E*** R******* Street",
"line": null
}
]
},
{
"name": "Email Address",
"label": "PII",
"count": 1,
"valueDetails": [
{
"masked_value": "t**t@b****l.com",
"line": null
}
]
}
],
"labels": [
"PII",
"Sensitive"
],
"isDbDump": false
}
],
"filesCount": 2
}
Human Readable Output
filename path type size openToWorld isDeleted isMalicious dataTypes labels isDbDump 268d4e2d-03f2-4044-b82d-8855b2e77f8d.csv 268d4e2d-03f2-4044-b82d-8855b2e77f8d.csv Data Format 17081 true false false IP Address (Sensitive), Internal IP Address (Sensitive) Sensitive false data security test cases.pdf data security test cases.pdf Document 73286 true false false Street Address (Sensitive), Email Address (PII) PII, Sensitive false
dspm-get-list-of-asset-fields-by-id
Return list of fields for structured assets such as RDS, Aurora, and BigQuery.
Base Command
dspm-get-list-of-asset-fields-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| assetId | ID of the asset for which to retrieve field details. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.AssetFields.name | String | Asset field name. |
| DSPM.AssetFields.path | String | Asset field path. |
| DSPM.AssetFields.tableName | String | Asset field table name. |
| DSPM.AssetFields.tableSize | String | Asset field table size. |
| DSPM.AssetFields.databaseName | String | Asset field database name. |
| DSPM.AssetFields.collectionName | String | Asset field collection name. |
| DSPM.AssetFields.type | String | Asset field type. |
| DSPM.AssetFields.dataTypes.name | String | Asset field data type name. |
| DSPM.AssetFields.dataTypes.label | String | Asset field data type label. |
| DSPM.AssetFields.dataTypes.hitPercentage | Number | Asset field data type hit percentage. |
| DSPM.AssetFields.dataTypes.maskedValues.masked_value | String | Asset field datat ype masked value. |
| DSPM.AssetFields.dataTypes.maskedValues.line | Number | Asset field data type masked value line. |
| DSPM.AssetFields.schemaName | String | Asset field schema name. |
Command example
!dspm-get-list-of-asset-fields-by-id assetId="arn:aws:rds:::dummyrds-cifp-us-east-1"
Context Example
{
"fields": [
{
"name": "maidenname",
"dataTypes": [],
"path": "/public/dummy",
"tableName": "dummy",
"tableSize": "29996",
"databaseName": "Hi",
"collectionName": null,
"type": "varchar",
"schemaName": "public"
},
{
"name": "phone",
"dataTypes": [],
"path": "/public/dummy",
"tableName": "dummy",
"tableSize": "29996",
"databaseName": "Hi",
"collectionName": null,
"type": "varchar",
"schemaName": "public"
}
],
"fieldsCount": 2
}
Human Readable Output
Asset Fields
| name | dataTypes | path | tableName | tableSize | databaseName | collectionName | type | schemaName |
|---|---|---|---|---|---|---|---|---|
| maidenname | [] | /public/dummy | dummy | 29996 | Hi | null | varchar | public |
| maidenname | [] | /public/dummy | dummy | 29996 | Hi | null | varchar | public |
dspm-get-data-types
Fetches the available data types for the DSPM integration.
Base Command
dspm-get-data-types
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.DataTypes.Key | String | Data types key. |
| DSPM.DataTypes.No | Number | Data types number. |
Command example
#### Context Example
```json
{
"DSPM": {
"DataTypes": [
{
"Key": "ID Number - Aadhaar (India)",
"No": 1
},
{
"Key": "Artifactory API Key",
"No": 2
},
{
"Key": "AWS Secret Key",
"No": 3
},
{
"Key": "Credit Card Expiration Date",
"No": 4
},
{
"Key": "Certificate",
"No": 5
}
]
}
}
Human Readable Output
Data Types
No Key 1 ID Number - Aadhaar (India) 2 Artifactory API Key 3 AWS Secret Key 4 Credit Card Expiration Date 5 Certificate
dspm-list-labels
Returns a list of label names based on the company.
Base Command
dspm-list-labels
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.Label.Key | String | Label key. |
| DSPM.Label.No | unknown | Label number. |
Command example
#### Context Example
```json
{
"DSPM": {
"Label": [
{
"Key": "PCI",
"No": 1
},
{
"Key": "PHI",
"No": 2
},
{
"Key": "PII",
"No": 3
},
{
"Key": "Confidential",
"No": 4
},
{
"Key": "Sensitive",
"No": 5
}
]
}
}
Human Readable Output
Data Types
No Key 1 PCI 2 PHI 3 PII 4 Confidential 5 Sensitive
dspm-list-data-types-findings
Retrieves a list of data type findings for the company.
Base Command
dspm-list-data-types-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| region_in | A comma-separated list of regions. | Optional |
| region_equal | The exact region. | Optional |
| cloud_provider_in | A comma-separated list of cloud providers. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| cloud_provider_equal | The exact cloud provider. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| service_type_in | A comma-separated list of service types. | Optional |
| service_type_equal | The exact service type. | Optional |
| lifecycle_in | A comma-separated list of life cycles. | Optional |
| projectId_in | A comma-separated list of project IDs. | Optional |
| projectId_equal | The exact project ID. | Optional |
| lifecycle_equal | The exact life cycle. | Optional |
| sort | The sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. | Optional |
| limit | The maximum number of data types findings to retrieve. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.DataTypesFinding.dataTypeName | String | Represents the name of the data type being analyzed. |
| DSPM.DataTypesFinding.label | String | Label associated with the data type, such as PII. |
| DSPM.DataTypesFinding.records | Integer | The number of records associated with the data type. |
| DSPM.DataTypesFinding.publicRecords | Integer | The number of public records found for this data type. |
| DSPM.DataTypesFinding.assets | Integer | The number of assets associated with this data type. |
| DSPM.DataTypesFinding.clouds | String | The clouds where the data type was found (e.g., AWS, Azure). |
| DSPM.DataTypesFinding.regions | String | The regions where the data type was found. |
| DSPM.DataTypesFinding.lastFound | Date | The timestamp when the data type was last found. |
| DSPM.DataTypesFinding.recordsAtRisk.high | Integer | The number of high-risk records found for this data type. |
| DSPM.DataTypesFinding.recordsAtRisk.medium | Integer | The number of medium-risk records found for this data type. |
| DSPM.DataTypesFinding.recordsAtRisk.low | Integer | The number of low-risk records found for this data type. |
Command example
!dspm-list-data-types-findings cloudProviderEqual=AWS
Context Example
[{
"dataTypeName": "AADHAAR_INDIVIDUAL_IDENTIFICATION",
"label": "PII",
"records": 4,
"publicRecords": 0,
"assets": 1,
"clouds": [
"AWS"
],
"regions": [
"us-east-1"
],
"lastFound": "2024-05-09T03:24:29Z",
"recordsAtRisk": {
"high": 0,
"medium": 4,
"low": 0
}
}]
Human Readable Output
Data Types Findings
| dataTypeName | label | records | publicRecords | assets | clouds | regions | lastFound | recordsAtRisk.high | recordsAtRisk.medium | recordsAtRisk.low |
|---|---|---|---|---|---|---|---|---|---|---|
| AADHAAR_INDIVIDUAL_IDENTIFICATION | PII | 4 | 0 | 1 | AWS | us-east-1 | 2024-05-09T03:24:29Z | 0 | 4 | 0 |
dspm-update-risk-finding-status
Updates the status of a risk finding.
Base Command
dspm-update-risk-finding-status
Input
| Argument Name | Description | Required |
|---|---|---|
| risk_finding_id | Risk Finding ID. | Required |
| status | List of supported statuses. Possible values are: OPEN, CLOSED, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.RiskFindingStatusUpdate.newStatus | String | Updated risk finding status. |
| DSPM.RiskFindingStatusUpdate.oldStatus | String | Old risk finding status. |
| DSPM.RiskFindingStatusUpdate.riskFindingId | String | Risk finding ID. |
Command example
!dspm-update-risk-finding-status riskFindingId="00000000-0000-4f99-0000-616843b6b19e" status=INVESTIGATING
Context Example
{
"DSPM": {
"RiskFindingStatusUpdate": {
"newStatus": "INVESTIGATING",
"oldStatus": "INVESTIGATING",
"riskFindingId": "00000000-0000-4f99-0000-616843b6b19e"
}
}
}
Human Readable Output
Risk Status Update
Risk Finding ID Old Status New Status 00000000-0000-4f99-0000-616843b6b19e INVESTIGATING INVESTIGATING
dspm-update-alert-status
Updates the status of an alert.
Base Command
dspm-update-alert-status
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_id | Alert ID. | Required |
| status | List of supported statuses. Possible values are: OPEN, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.AlertStatusUpdate.newStatus | String | Updated alert status. |
| DSPM.AlertStatusUpdate.oldStatus | String | Old alert status. |
| DSPM.AlertStatusUpdate.alertId | String | Alert ID. |
Command example
!dspm-update-alert-status alertId="000000608" status=INVESTIGATING
Context Example
{
"DSPM": {
"AlertStatusUpdate": {
"newStatus": "INVESTIGATING",
"oldStatus": "INVESTIGATING",
"alertId": "000000608"
}
}
}
Human Readable Output
Alert Status Update
Alert ID Old Status New Status 000000608 INVESTIGATING INVESTIGATING
dspm-list-alerts
Fetch list of alerts.
Base Command
dspm-list-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| detection_time_equals | The exact detection time (equals). detection time format - YYYY-MM-DDTHH:MM:SSZ. | Optional |
| detection_time_greater_than_or_equal | Detection time (greater than or equal). detection time format - YYYY-MM-DDTHH:MM:SSZ. | Optional |
| detection_time_greater_than | Detection time (greater than). detection time format - YYYY-MM-DDTHH:MM:SSZ. | Optional |
| detection_time_less_than_or_equal | Detection time (less than or equal). detection time format - YYYY-MM-DDTHH:MM:SSZ. | Optional |
| detection_time_less_than | Detection time (less than). detection time format - YYYY-MM-DDTHH:MM:SSZ. | Optional |
| policy_name_in | A comma-separated list of policy names. | Optional |
| policy_name_equals | The exact policy name. | Optional |
| asset_name_in | A comma-separated list of asset names. | Optional |
| asset_name_equals | The exact asset name. | Optional |
| cloud_provider_in | A comma-separated list of cloud providers. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| cloud_provider_equals | The exact cloud provider. Possible values are: AWS, AZURE, GCP, SNOWFLAKE, FILE_SHARE, O365. | Optional |
| destination_project_vendor_name_in | A comma-separated list of project vendor names. | Optional |
| destination_project_vendor_name_equals | The exact destination project vendor name. | Optional |
| cloud_environment_in | A comma-separated list of cloud environments. Possible values are: UNKNOWN, DEVELOPMENT, STAGING, TESTING, PRODUCTION. | Optional |
| cloud_environment_equals | The exact cloud environment. Possible values are: UNKNOWN, DEVELOPMENT, STAGING, TESTING, PRODUCTION. | Optional |
| policy_severity_in | A comma-separated list of policy severities. Possible values are: HIGH, MEDIUM, LOW. | Optional |
| policy_severity_equals | The exact policy severity. Possible values are: HIGH, MEDIUM, LOW. | Optional |
| category_type_in | A comma-separated list of category types. Possible values are: FIRST_MOVE, ATTACK, COMPLIANCE, ASSET_AT_RISK, RECONNAISSANCE. | Optional |
| category_type_equals | The exact category type. Possible values are: FIRST_MOVE, ATTACK, COMPLIANCE, ASSET_AT_RISK, RECONNAISSANCE. | Optional |
| status_in | A comma-separated list of statuses. Possible values are: OPEN, CLOSED, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Optional |
| status_equals | The exact status. Possible values are: OPEN, CLOSED, UNIMPORTANT, WRONG, HANDLED, INVESTIGATING. | Optional |
| sort | Sort order (property,asc|desc). | Optional |
| limit | The maximum number of alerts to retrieve. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DSPM.Alert.id | String | Alert ID. |
| DSPM.Alert.detectionTime | Date | Alert detection time. |
| DSPM.Alert.policyName | String | Alert policy name. |
| DSPM.Alert.assetName | String | Alert asset name. |
| DSPM.Alert.assetLabels | Unknown | Alert asset label. |
| DSPM.Alert.cloudProvider | String | Alert cloud provider. |
| DSPM.Alert.destinationProjects | Unknown | Alert destination projects. |
| DSPM.Alert.cloudEnvironment | String | Alert cloud enviroment. |
| DSPM.Alert.policySeverity | String | Alert policy severity. |
| DSPM.Alert.policyCategoryType | String | Alert policy category type. |
| DSPM.Alert.status | String | Alert status. |
| DSPM.Alert.eventActor | String | Alert event actor. |
| DSPM.Alert.eventUserAgent | String | Alert event user agent. |
| DSPM.Alert.eventActionMedium | String | Alert event action medium. |
| DSPM.Alert.eventSource | String | Alert event source. |
| DSPM.Alert.policyFrameWorks | String | Alert policy frameworks. |
| DSPM.Alert.eventRawData | String | Alert event raw data. |
Command example
!dspm-list-alerts cloudEnvironmentEquals="TESTING"
Context Example
{
"DSPM": {
"Alerts": [
{
"id": "340256006",
"detectionTime": "2024-08-07T18:55:50.64996Z",
"policyName": "Asset made public",
"assetName": "mikeys3",
"assetLabels": [],
"cloudProvider": "AWS",
"destinationProjects": {},
"cloudEnvironment": "TESTING",
"policySeverity": "HIGH",
"policyCategoryType": "ATTACK",
"status": "OPEN",
"eventActor": "dummy_email",
"eventUserAgent": "[S3Console/0.4, aws-internal/3 aws-sdk-java/1.12.488 Linux/5.10.220-187.867.amzn2int.x86_64 OpenJDK_64-Bit_Server_VM/25.372-b08 java/1.8.0_372 vendor/Oracle_Corporation cfg/retry-mode/standard]",
"eventActionMedium": "CONSOLE",
"eventSource": "***.**.**.***.***",
"policyFrameWorks": [
"MITRE-T1098"
],
"eventRawData": "{\"eventVersion\":\"1.09\",\"userIdentity\":{\"type\":\"AssumedRole\",\"principalId\":\"AROASI3QR4HKUAIEPBICG:dummy_email\",\"arn\":\"arn:aws:sts::576847873638:assumed-role/sso_admin-tac-nam/dummy_email\",\"accountId\":\"576847873638\",\"accessKeyId\":\"ASIASI3QR4HK2LDI5JMN\",\"sessionContext\":{\"sessionIssuer\":{\"type\":\"Role\",\"principalId\":\"AROASI3QR4HKUAIEPBICG\",\"arn\":\"arn:aws:iam::576847873638:role/sso_admin-tac-nam\",\"accountId\":\"576847873638\",\"userName\":\"sso_admin-tac-nam\"},\"attributes\":{\"creationDate\":\"2024-08-07T18:51:51Z\",\"mfaAuthenticated\":\"false\"}}},\"eventTime\":\"2024-08-07T18:55:37Z\",\"eventSource\":\"s3.amazonaws.com\",\"eventName\":\"PutBucketPolicy\",\"awsRegion\":\"us-east-1\",\"sourceIPAddress\":\"***.**.**.***.***\",\"userAgent\":\"[S3Console/0.4, aws-internal/3 aws-sdk-java/1.12.488 Linux/5.10.220-187.867.amzn2int.x86_64 OpenJDK_64-Bit_Server_VM/25.372-b08 java/1.8.0_372 vendor/Oracle_Corporation cfg/retry-mode/standard]\",\"requestParameters\":{\"bucketPolicy\":{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Statement1\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListBucketMultipartUploads\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::mikeys3\",\"arn:aws:s3:::mikeys3/*\"]}]},\"bucketName\":\"mikeys3\",\"Host\":\"s3.amazonaws.com\",\"policy\":\"\"},\"responseElements\":null,\"additionalEventData\":{\"SignatureVersion\":\"SigV4\",\"CipherSuite\":\"TLS_AES_128_GCM_SHA256\",\"bytesTransferredIn\":568,\"AuthenticationMethod\":\"AuthHeader\",\"x-amz-id-2\":\"KXHYo+o2L/Gnk0pmKY+gV+0YufF6uGyD3GRwK+FXEJ7eai772ytOzbV9CwwoezhB5PPR/6RxZyhOyBowBOyQih\",\"bytesTransferredOut\":0},\"requestID\":\"CJ3J7M851NAGAF58\",\"eventID\":\"df06b9ad-79dc-4a17-ae0e-82ecff9cfa5e\",\"readOnly\":false,\"resources\":[{\"accountId\":\"576847873638\",\"type\":\"AWS::S3::Bucket\",\"ARN\":\"arn:aws:s3:::mikeys3\"}],\"eventType\":\"AwsApiCall\",\"managementEvent\":true,\"recipientAccountId\":\"576847873638\",\"vpcEndpointId\":\"vpce-f40dc59d\",\"eventCategory\":\"Management\",\"tlsDetails\":{\"tlsVersion\":\"TLSv1.3\",\"cipherSuite\":\"TLS_AES_128_GCM_SHA256\",\"clientProvidedHostHeader\":\"s3.amazonaws.com\"}}"
}
]
}
}
Human Readable Output
DSPM Alert
Alert ID Detection Time Policy Name Asset Name Cloud Provider Cloud Environment Policy Severity Policy Category Status Event Actor Event Action Medium Event Source Policy Frameworks eventRawData 340256006 2024-08-07T18:55:50.64996Z Asset made public mikeys3 AWS TESTING HIGH ATTACK OPEN dummy_email CONSOLE .**.**..*** MITRE-T1098 ”{"eventVersion":"1.09","userIdentity":{"type":"AssumedRole","principalId":"AROASI3QR4HKUAIEPBICG:dummy_email","arn":"arn:aws:sts::576847873638:assumed-role/sso_admin-tac-nam/dummy_email","accountId":"576847873638","accessKeyId":"ASIASI3QR4HK2LDI5JMN","sessionContext":{"sessionIssuer":{"type":"Role","principalId":"AROASI3QR4HKUAIEPBICG","arn":"arn:aws:iam::576847873638:role/sso_admin-tac-nam","accountId":"576847873638","userName":"sso_admin-tac-nam"},"attributes":{"creationDate":"2024-08-07T18:51:51Z","mfaAuthenticated":"false"}}},"eventTime":"2024-08-07T18:55:37Z","eventSource":"s3.amazonaws.com","eventName":"PutBucketPolicy","awsRegion":"us-east-1","sourceIPAddress":".**.**..**","userAgent":"[S3Console/0.4, aws-internal/3 aws-sdk-java/1.12.488 Linux/5.10.220-187.867.amzn2int.x86_64 OpenJDK_64-Bit_Server_VM/25.372-b08 java/1.8.0_372 vendor/Oracle_Corporation cfg/retry-mode/standard]","requestParameters":{"bucketPolicy":{"Version":"2012-10-17","Statement":[{"Sid":"Statement1","Effect":"Allow","Principal":"","Action":["s3:AbortMultipartUpload","s3:DeleteObject","s3:GetObject","s3:ListBucketMultipartUploads","s3:ListMultipartUploadParts","s3:PutObject"],"Resource":["arn:aws:s3:::mikeys3","arn:aws:s3:::mikeys3/*"]}]},"bucketName":"mikeys3","Host":"s3.amazonaws.com","policy":""},"responseElements":null,"additionalEventData":{"SignatureVersion":"SigV4","CipherSuite":"TLS_AES_128_GCM_SHA256","bytesTransferredIn":568,"AuthenticationMethod":"AuthHeader","x-amz-id-2":"KXHYo+o2TWL/Gnk0pmKY+gV+0YufF6uGyD3GRwK+FXEJ7eai772ytOzbV9CwwoBq+pezhB5PPR/6RxZyhOyZltIBowBOyQih","bytesTransferredOut":0},"requestID":"CJ3J7M851NAGAF58","eventID":"df06b9ad-79dc-4a17-ae0e-82ecff9cfa5e","readOnly":false,"resources":[{"accountId":"576847873638","type":"AWS::S3::Bucket","ARN":"arn:aws:s3:::mikeys3"}],"eventType":"AwsApiCall","managementEvent":true,"recipientAccountId":"576847873638","vpcEndpointId":"vpce-f40dc59d","eventCategory":"Management","tlsDetails":{"tlsVersion":"TLSv1.3","cipherSuite":"TLS_AES_128_GCM_SHA256","clientProvidedHostHeader":"s3.amazonaws.com"}}”
Configuration parameters
dspmBaseUrl— Your DSPM server URL (required)dspmApiKey— (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidents
Commands (12)
-
dspm-get-asset-detailsRetrieves details for the specified asset ID.
-
dspm-get-asset-files-by-idRetrieves file details for the specified asset ID.
-
dspm-get-data-typesFetches the available data types for the DSPM integration.
-
dspm-get-list-of-asset-fields-by-idReturn list of fields for structured assets such as RDS, Aurora, and BigQuery.
-
dspm-get-risk-finding-by-idRetrieves the details of a risk for the provided risk ID.
-
dspm-list-alertsFetch list of alerts.
-
dspm-list-assetsRetrieves a list of assets for the company.
-
dspm-list-data-types-findingsRetrieves a list of data type findings for the company.
-
dspm-list-labelsReturns a list of label names based on the company.
-
dspm-list-risk-findingsRetrieves risk findings matching the input criteria.
-
dspm-update-alert-statusUpdates the status of an alert.
-
dspm-update-risk-finding-statusUpdates the status of a risk finding.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa: F401 import urllib3 from typing import Any import re # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ MAX_PAGE_SIZE: int = 50 DEFAULT_LIMIT: str = "50" DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR GET_RISK_FINDINGS_ENDPOINT = "/v1/risk-findings" GET_ASSET_LISTS = "/v1/assets" GET_ASSET_DETAILS = "/v1/assets/id?id=" GET_ASSET_FILES = "/v1/classification/asset-files/id" GET_ASSET_FIELDS = "/v1/classification/asset-fields/id" GET_DATA_TYPES_ENDPOINT: str = "/v1/classification/data-types" GET_DATA_TYPE_FINDINGS_ENDPOINT: str = "/v1/data-type-findings" GET_ALERTS_LIST: str = "/v1/alerts" GET_LABELS: str = "/v1/labels" GET_RISK_FINDING_BY_ID: str = "/v1/risk-findings/id/" SUPPORTED_CLOUD_PROVIDERS = ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"] SUPPORTED_CATEGORIES = [ "SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE", "SECURITY_AND_COMPLIANCE_AND_GOVERNANCE", ] SUPPORTED_SERVICE_TYPES = [ "ATHENA", "AURORA", "AWS_BACKUP", "DOCUMENTDB", "DYNAMODB", "DAX", "EMR", "EBS", "EFS", "ELASTICACHE", "FSX", "KINESIS_DELIVERY_STREAM", "MEMORYDB", "NEPTUNE", "QLDB", "RDS", "REDSHIFT", "S3", "TIMESTREAM", "OPENSEARCH", "COSMOS_DB", "SYNAPSE", "CACHE_FOR_REDIS", "MARIA_DB", "MYSQL_SERVER", "POSTGRESQL_SERVER", "SQL_SERVER", "STORAGE_ACCOUNT", "SQL_MANAGED_INSTANCE", "ANF", "CLOUD_STORAGE", "CLOUD_SQL", "BIG_QUERY", "FILE_STORE", "CLOUD_SPANNER", "MEMORY_STORE", "BIG_TABLE", "FIRE_STORE", "UNMANAGED_AWS_MYSQL", "UNMANAGED_AWS_ORACLE_SERVER", "UNMANAGED_AWS_MONGO_DB", "UNMANAGED_AWS_POSTGRESQL", "UNMANAGED_AWS_REDIS", "UNMANAGED_AWS_SQLITE", "UNMANAGED_AWS_MS_SQL", "UNMANAGED_AWS_MARIA_DB", "UNMANAGED_AWS_NEO4_J", "UNMANAGED_AWS_ELASTIC", "UNMANAGED_AWS_COCKROACH_DB", "UNMANAGED_AWS_AEROSPIKE", "UNMANAGED_AWS_SCYLLA_DB", "UNMANAGED_AZURE_MYSQL", "UNMANAGED_AZURE_ORACLE_SERVER", "UNMANAGED_AZURE_MONGO_DB", "UNMANAGED_AZURE_POSTGRESQL", "UNMANAGED_AZURE_REDIS", "UNMANAGED_AZURE_SQLITE", "UNMANAGED_AZURE_MS_SQL", "UNMANAGED_AZURE_MARIA_DB", "UNMANAGED_AZURE_NEO4_J", "UNMANAGED_AZURE_ELASTIC", "UNMANAGED_AZURE_COCKROACH_DB", "UNMANAGED_AZURE_AEROSPIKE", "UNMANAGED_AZURE_SCYLLA_DB", "UNMANAGED_GCP_MYSQL", "UNMANAGED_GCP_ORACLE_SERVER", "UNMANAGED_GCP_MONGO_DB", "UNMANAGED_GCP_POSTGRESQL", "UNMANAGED_GCP_REDIS", "UNMANAGED_GCP_SQLITE", "UNMANAGED_GCP_MS_SQL", "UNMANAGED_GCP_MARIA_DB", "UNMANAGED_GCP_NEO4_J", "UNMANAGED_GCP_ELASTIC", "UNMANAGED_GCP_COCKROACH_DB", "UNMANAGED_GCP_AEROSPIKE", "UNMANAGED_GCP_SCYLLA_DB", "SNOWFLAKE_DB", "FILE_SHARE", "ONE_DRIVE", "SHARE_POINT", "AZURE_OPEN_AI_DEPLOYMENT", "VERTEX_ENDPOINT", ] SUPPORTED_LIFECYCLE = ["RUNNING", "STOPPED", "DELETED"] SUPPORTED_STATUSES = [ "OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING", ] SUPPORTED_CLOUD_ENVIRONMENTS = ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"] SUPPORTED_POLICY_SEVERITIES = ["HIGH", "MEDIUM", "LOW"] SUPPORTED_CATEGORY_TYPES = ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"] """ CLIENT CLASS """ class Client(BaseClient): """Client class to interact with the service API""" def __init__(self, base_url, api_key, verify=True, proxy=False): headers = {"dig-api-key": api_key, "Accept": "application/json"} super().__init__(base_url, verify=verify, headers=headers, proxy=proxy) def get_labels(self): return self._http_request(method="GET", url_suffix=f"{GET_LABELS}") def fetch_risk_findings(self, params: dict[str, Any]): demisto.debug(f"all params : {params}") return self._http_request(method="GET", url_suffix=f"{GET_RISK_FINDINGS_ENDPOINT}", params=params) def get_asset_files(self, params: dict[str, Any]): return self._http_request(method="POST", url_suffix=f"{GET_ASSET_FILES}", params=params) def get_asset_details(self, asset_id: str): return self._http_request(method="GET", url_suffix=f"{GET_ASSET_DETAILS}{asset_id}") def get_asset_lists(self, params: dict[str, Any]): return self._http_request(method="GET", url_suffix=f"{GET_ASSET_LISTS}", params=params) def get_data_types(self): return self._http_request( method="GET", url_suffix=f"{GET_DATA_TYPES_ENDPOINT}", ) def get_data_type_findings(self, params: dict[str, Any]): return self._http_request(method="GET", url_suffix=f"{GET_DATA_TYPE_FINDINGS_ENDPOINT}", params=params) def get_risk_information(self, risk_id: str): """ Retrieve a risk finding by its ID from Dig Security. :param incident_id: The ID of the incident to retrieve. :return: The incident data as a dictionary. """ return self._http_request(method="GET", url_suffix=f"{GET_RISK_FINDING_BY_ID}{risk_id}") def update_risk_status(self, risk_id: str, updated_status: str): return self._http_request( method="PATCH", url_suffix=f"/v1/risk-findings/id/{risk_id}/status/{updated_status}", ) def get_alerts_list(self, params: dict[str, Any]): return self._http_request(method="GET", url_suffix=f"{GET_ALERTS_LIST}", params=params) def update_alert_status(self, alert_id: str, updated_status: str): return self._http_request( method="PATCH", url_suffix=f"/v1/alerts/id/{alert_id}/status/{updated_status}", ) def get_list_of_asset_fields(self, params): return self._http_request(method="POST", url_suffix=f"{GET_ASSET_FIELDS}", params=params) """ HELPER FUNCTIONS """ def validate_parameter(param_name: str, param_in: str, param_equal: str, supported_list: list[str]): if param_in: param_list = [item.strip() for item in param_in.split(",") if item.strip()] for param in param_list: if param not in supported_list: raise ValueError(f'This "{param}" {param_name} is not supported') if param_equal and param_equal not in supported_list: raise ValueError(f'This "{param_equal}" {param_name} is not supported') """ COMMAND FUNCTIONS """ def test_module(client: Client) -> str: """Tests API connectivity and authentication""" try: # validate dspm creds client.get_data_types() return "ok" except DemistoException as e: if "Forbidden" in str(e) or "Authorization" in str(e): return "Authorization Error: make sure DSPM API Key is correctly set" else: return f"Error: An unknown exception occurred: {e}" def get_list_risk_findings(client: Client, args: dict[str, Any], page: int) -> list[dict]: """Fetch list of DSPM Risk findings""" # Validate and process cloudProvider parameters cloud_provider_in = args.get("cloud_provider_in", "") cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter("cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS) # Check supported affects affects_in = args.get("affects_in", "") affects_equal = args.get("affects_equal", "") validate_parameter("affects", affects_in, affects_equal, SUPPORTED_CATEGORIES) # Check supported Status status_in = args.get("status_in", "") status_equal = args.get("status_equal", "") validate_parameter("status", status_in, status_equal, SUPPORTED_STATUSES) # Check supported sorting order sort_order = args.get("sort") if sort_order: pattern = r"^.*,(ASC|DESC)$" matches = re.findall(pattern, sort_order, re.IGNORECASE) # type: ignore if not matches: raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { "ruleName.in": args.get("rule_name_in"), "ruleName.equals": args.get("rule_name_equal"), "dspmTagKey.in": args.get("dspm_tag_key_in"), "dspmTagKey.equals": args.get("dspm_tag_key_equal"), "dspmTagValue.in": args.get("dspm_tag_value_in"), "dspmTagValue.equals": args.get("dspm_tag_value_equal"), "projectId.in": args.get("projectId_in"), "projectId.equals": args.get("projectId_equal"), "cloudProvider.in": args.get("cloud_provider_in"), "cloudProvider.equals": args.get("cloud_provider_equal"), "affects.in": args.get("affects_in"), "affects.equals": args.get("affects_equal"), "status.in": args.get("status_in"), "status.equals": args.get("status_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, } # Remove None values from params params = {k: v for k, v in params.items() if v is not None} demisto.debug(f"params : {params}") # Fetch data from client findings = client.fetch_risk_findings(params) if not findings: return [] # No more findings to fetch return findings def get_risk_finding_by_id(client: Client, args: dict[str, Any]) -> CommandResults: risk_id = args.get("finding_id") if not risk_id: raise ValueError("finding_id argument is required") # Fetch data from client using the get_risk_information method response = client.get_risk_information(risk_id) if not response: raise ValueError(f"No risk found with id {risk_id}") finding = response if isinstance(response, dict) else response[0] readable_output = tableToMarkdown("Risk Finding", finding, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.RiskFinding", outputs_key_field="id", outputs=finding, readable_output=readable_output, raw_response=finding, ) def get_list_of_assets(client: Client, args: dict[str, Any], page: int) -> list[dict]: # Validate and process cloudProvider parameters cloud_provider_in = args.get("cloud_provider_in", "") cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter("cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS) # Validate and process serviceType parameters service_Type_In = args.get("service_type_in", "") service_Type_Equal = args.get("service_type_equal", "") validate_parameter("serviceType", service_Type_In, service_Type_Equal, SUPPORTED_SERVICE_TYPES) # Validate and process lifecycle parameters lifecycle_In = args.get("lifecycle_in", "") lifecycle_Equal = args.get("lifecycle_equal", "") validate_parameter("lifecycle", lifecycle_In, lifecycle_Equal, SUPPORTED_LIFECYCLE) # Check supported sorting order sort_order = args.get("sort") if sort_order: pattern = r"^.*,(ASC|DESC)$" matches = re.findall(pattern, sort_order, re.IGNORECASE) # type: ignore if not matches: raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { "region.in": args.get("region_in"), "region.equals": args.get("region_equal"), "cloudProvider.in": args.get("cloud_provider_in"), "cloudProvider.equals": args.get("cloud_provider_equal"), "serviceType.in": args.get("service_type_in"), "serviceType.equals": args.get("service_type_equal"), "digTagKey.contains": args.get("dig_tag_key_contains"), "digTagValue.contains": args.get("dig_tag_value_contains"), "lifecycle.in": args.get("lifecycle_in"), "lifecycle.equals": args.get("lifecycle_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, } # Remove None values from params params = {k: v for k, v in params.items() if v is not None} # Fetch data from client response = client.get_asset_lists(params) assets = response.get("assets", []) if isinstance(response, dict) else response if not assets: return [] # No more assets to fetch return assets def get_asset_details(client: Client, args: dict[str, Any]) -> CommandResults: asset_id = args.get("asset_id", None) if not asset_id: raise ValueError("asset_id not specified") asset_details = client.get_asset_details(asset_id) readable_output = tableToMarkdown("Asset Details", asset_details, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.AssetDetails", outputs_key_field="id", outputs=asset_details, readable_output=readable_output, raw_response=asset_details, ) def get_asset_files_by_id(client: Client, args: dict[str, Any]) -> CommandResults: asset_id = args.get("asset_id", None) if not asset_id: raise ValueError("Asset ID not specified") page_number = 1 all_files = [] while True: params = {"id": asset_id, "page": page_number, "size": MAX_PAGE_SIZE} # Fetch the asset files for the current page response = client.get_asset_files(params) files = response.get("files", []) if not files: break # Stop when there are no more files to retrieve # Append the files to the total list of files all_files.extend(files) # Increment page number for the next fetch page_number += 1 files_count = len(all_files) # Return the result without formatting the files structure readable_output = tableToMarkdown("Asset Files", all_files, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.AssetFiles", outputs_key_field="filename", outputs={"files": all_files, "filesCount": files_count}, readable_output=readable_output, raw_response=all_files, ) def get_data_types(client: Client) -> CommandResults: """Command to fetch data types.""" data_types = client.get_data_types() data_types_formatted = [{"No": index + 1, "Key": dt} for index, dt in enumerate(data_types)] table_name = "Data Types" headers = ["No", "Key"] readable_output = tableToMarkdown(table_name, data_types_formatted, headers=headers) return CommandResults( outputs_prefix="DSPM.DataTypes", outputs_key_field="Key", outputs=data_types_formatted, readable_output=readable_output, raw_response=data_types, ) def get_data_type_findings(client: Client, args: dict[str, Any], page: int) -> list[dict]: """Fetch data type findings for a specific page.""" # check supported cloud providers cloud_provider_in = args.get("cloud_provider_in", "") cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter("cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS) # check supported service type service_type_in = args.get("service_type_in", "") service_type_equal = args.get("service_type_equal", "") validate_parameter("serviceType", service_type_in, service_type_equal, SUPPORTED_SERVICE_TYPES) # check supported lifecycle lifecycle_in = args.get("lifecycle_in", "") lifecycle_equal = args.get("lifecycle_equal", "") validate_parameter("lifecycle", lifecycle_in, lifecycle_equal, SUPPORTED_LIFECYCLE) # Check supported sorting order sort_order = args.get("sort") if sort_order: pattern = r"^.*,(ASC|DESC)$" matches = re.findall(pattern, sort_order, re.IGNORECASE) # type: ignore if not matches: raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { "region.in": args.get("region_in"), "region.equals": args.get("region_equal"), "projectId.in": args.get("projectId_in"), "projectId.equals": args.get("projectId_equal"), "cloudProvider.in": args.get("cloud_provider_in"), "cloudProvider.equals": args.get("cloud_provider_equal"), "serviceType.in": args.get("service_type_in"), "serviceType.equals": args.get("service_type_equal"), "lifecycle.in": args.get("lifecycle_in"), "lifecycle.equals": args.get("lifecycle_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, } # Remove None values from params params = {k: v for k, v in params.items() if v is not None} data_type_findings = client.get_data_type_findings(params) return data_type_findings def update_risk_finding_status(client, args): finding_id = args.get("risk_finding_id") status = args.get("status") if status and status not in SUPPORTED_STATUSES: raise ValueError(f'This "{status}" status is not supported') try: response = client.update_risk_status(finding_id, status) # Format the response for display markdown = tableToMarkdown("Risk Status Update", [response], headerTransform=pascalToSpace) return CommandResults( readable_output=markdown, outputs_prefix="DSPM.RiskFindingStatusUpdate", outputs_key_field="riskFindingId", outputs=response, raw_response=response, ) except Exception as e: return_error(f"Failed to update risk finding {finding_id} to status {status}. Error: {str(e)}") def get_list_of_alerts(client: Client, args: dict[str, Any], page: int) -> list[dict]: """fetch list of dspm alerts""" # check supported cloud providers cloud_provider_in = args.get("cloud_provider_in", "") cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter("cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS) # check supported cloud environments cloud_environment_in = args.get("cloud_environment_in", "") cloud_environment_equal = args.get("cloud_environment_equal", "") validate_parameter("cloudEnvironment", cloud_environment_in, cloud_environment_equal, SUPPORTED_CLOUD_ENVIRONMENTS) # check supported policy severity policy_severity_in = args.get("policy_severity_in", "") policy_severity_equal = args.get("policy_severity_equal", "") validate_parameter("policySeverity", policy_severity_in, policy_severity_equal, SUPPORTED_POLICY_SEVERITIES) # check supported category type category_type_in = args.get("category_type_in", "") category_type_equal = args.get("category_type_equal", "") validate_parameter("categoryType", category_type_in, category_type_equal, SUPPORTED_CATEGORY_TYPES) # check supported category type status_in = args.get("status_in", "") status_equal = args.get("status_equal", "") validate_parameter("status", status_in, status_equal, SUPPORTED_STATUSES) # Check supported sorting order sort_order = args.get("sort") if sort_order: pattern = r"^.*,(ASC|DESC)$" matches = re.findall(pattern, sort_order, re.IGNORECASE) # type: ignore if not matches: raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { "detectionTime.equals": args.get("detection_time_equals"), "detectionTime.greaterThanOrEqual": args.get("detection_time_greater_than_or_equal"), "detectionTime.greaterThan": args.get("detection_time_greater_than"), "detectionTime.lessThanOrEqual": args.get("detection_time_less_than_or_equal"), "detectionTime.lessThan": args.get("detection_time_less_than"), "policyName.in": args.get("policy_name_in"), "policyName.equals": args.get("policy_name_equals"), "assetName.in": args.get("asset_name_in"), "assetName.equals": args.get("asset_name_equals"), "cloudProvider.in": args.get("cloud_provider_in"), "cloudProvider.equals": args.get("cloud_provider_equals"), "destinationProjectVendorName.in": args.get("destination_project_vendor_name_in"), "destinationProjectVendorName.equals": args.get("destination_project_vendor_name_equals"), "cloudEnvironment.in": args.get("cloud_environment_in"), "cloudEnvironment.equals": args.get("cloud_environment_equals"), "policySeverity.in": args.get("policy_severity_in"), "policySeverity.equals": args.get("policy_severity_equals"), "categoryType.in": args.get("category_type_in"), "categoryType.equals": args.get("category_type_equals"), "status.in": args.get("status_in"), "status.equals": args.get("status_equals"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, } # Remove None values from params params = {k: v for k, v in params.items() if v is not None} alerts_list = client.get_alerts_list(params) return alerts_list def update_dspm_alert_status(client, args): alert_id = args.get("alert_id") status = args.get("status") if status and status not in SUPPORTED_STATUSES: raise ValueError(f'This "{status}" status is not supported') try: response = client.update_alert_status(alert_id, status) # Format the response for display markdown = tableToMarkdown("Alert Status Update", [response], headerTransform=pascalToSpace) return CommandResults( readable_output=markdown, outputs_prefix="DSPM.AlertStatusUpdate", outputs_key_field="alertId", outputs=response, raw_response=response, ) except Exception as e: return_error(f"Failed to update alert '{alert_id}' to status '{status}'. Error: {str(e)}") def get_list_of_labels(client: Client): """Command to fetch list of label names based on company""" labels = client.get_labels() labels_formatted = [{"No": index + 1, "Key": dt} for index, dt in enumerate(labels)] table_name = "Labels" headers = ["No", "Key"] readable_output = tableToMarkdown(table_name, labels_formatted, headers=headers) return CommandResults( outputs_prefix="DSPM.Label", outputs_key_field="Key", outputs=labels_formatted, readable_output=readable_output, raw_response=labels, ) def dspm_list_risk_findings_command(client, args): limit = args.get("limit", DEFAULT_LIMIT) if not limit.isdigit(): raise ValueError("The 'limit' parameter must be an integer.") limit = int(limit) page = 0 findings_collected: list = [] while len(findings_collected) < limit: findings = get_list_risk_findings(client, args, page) if not findings: if page == 0 and not findings_collected: demisto.info("No risks were fetched") return CommandResults(readable_output="No Risk Findings found.") break # No more findings to fetch findings_collected.extend(findings) if len(findings_collected) >= limit: break page += 1 # Trim findings to match the limit findings_collected = findings_collected[:limit] # Prepare the readable output readable_output = tableToMarkdown("Risk Findings", findings_collected, headerTransform=pascalToSpace) # Return a single CommandResults with all findings return CommandResults( outputs_prefix="DSPM.RiskFinding", outputs_key_field="id", outputs=findings_collected, readable_output=readable_output, raw_response=findings_collected, ) def dspm_list_assets_command(client, args): limit = args.get("limit", DEFAULT_LIMIT) if not limit.isdigit(): raise ValueError("The 'limit' parameter must be an integer.") limit = int(limit) page = 0 collected_assets: list = [] while len(collected_assets) < limit: assets = get_list_of_assets(client, args, page) if not assets: if page == 0 and not collected_assets: return CommandResults(readable_output="No assets found.") break collected_assets.extend(assets) if len(collected_assets) >= limit: break page += 1 # Trim the results to match the limit collected_assets = collected_assets[:limit] # Generate readable output readable_output = tableToMarkdown("List of Assets", collected_assets, headerTransform=pascalToSpace) # Return the collected assets directly without parsing return CommandResults( outputs_prefix="DSPM.Asset", outputs_key_field="id", outputs=collected_assets, readable_output=readable_output, raw_response=collected_assets, ) def dspm_list_data_types_findings_command(client, args): limit = args.get("limit", DEFAULT_LIMIT) if not limit.isdigit(): raise ValueError("The 'limit' parameter must be an integer.") limit = int(limit) page = 0 collected_data_types: list = [] while len(collected_data_types) < limit: data_type_findings = get_data_type_findings(client, args, page) if not data_type_findings: if page == 0 and not collected_data_types: return CommandResults( readable_output="No Data Types findings found.", ) break collected_data_types.extend(data_type_findings) if len(collected_data_types) >= limit: break page += 1 # Trim the results to match the limit collected_data_types = collected_data_types[:limit] readable_output = tableToMarkdown("Data Types Finding", collected_data_types, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.DataTypesFinding", outputs_key_field="dataTypeName", outputs=collected_data_types, readable_output=readable_output, raw_response=collected_data_types, ) def dspm_list_alerts_command(client, args): limit = args.get("limit", DEFAULT_LIMIT) if not limit.isdigit(): raise ValueError("The 'limit' parameter must be an integer.") limit = int(limit) page = 0 collected_alerts: list = [] while len(collected_alerts) < limit: alerts = get_list_of_alerts(client, args, page) if not alerts: if page == 0 and not collected_alerts: return CommandResults( readable_output="No alerts found.", ) break collected_alerts.extend(alerts) if len(collected_alerts) >= limit: break page += 1 # Trim the results to match the limit collected_alerts = collected_alerts[:limit] readable_output = tableToMarkdown("List Of Alerts", collected_alerts, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.Alert", outputs_key_field="id", outputs=collected_alerts, readable_output=readable_output, raw_response=collected_alerts, ) def dspm_get_list_of_asset_fields_command(client: Client, args: dict[str, Any]) -> CommandResults: asset_id = args.get("assetId", None) if not asset_id: raise ValueError("Asset ID not specified") page_number = 1 all_fields = [] try: while True: params = {"id": asset_id, "page": page_number, "size": MAX_PAGE_SIZE} # Fetch the asset fields for the current page response = client.get_list_of_asset_fields(params) if isinstance(response, list) and len(response) > 0: fields = response[0].get("fields", []) else: fields = response.get("fields", []) # fields = response[0].get("fields", []) if not fields: break # Append the fields to the total list of fields all_fields.extend(fields) # Increment page number for the next fetch page_number += 1 fields_count = len(all_fields) # Return the result without formatting the fields structure headers = ["name", "dataTypes", "path", "tableName", "tableSize", "databaseName", "collectionName", "type", "schemaName"] readable_output = tableToMarkdown("Asset Field", all_fields, headers=headers, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.AssetFields", outputs_key_field="name", outputs={"fields": all_fields, "fieldsCount": fields_count}, readable_output=readable_output, ) except Exception as e: error = str(e) if '"status": 400' in error: message = f"Provided assetID:- '{asset_id}' does not supported. Please check the command description for more details" elif '"status": 404' in error: message = f"Incorrect assetID:- '{asset_id}' provided. Please confirm the assetID" else: message = f"Failed to get asset fields for assetId:- '{asset_id}'. Error: {str(e)}" raise Exception(message) """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ # get the service API url base_url = demisto.params().get("dspmBaseUrl") api_key = demisto.params().get("dspmApiKey", {}).get("password") verify_certificate = not demisto.params().get("insecure", False) proxy = demisto.params().get("proxy", False) demisto.debug(f"Command being called is {demisto.command()}") try: client = Client(base_url=base_url, api_key=api_key, verify=verify_certificate, proxy=proxy) if demisto.command() == "test-module": result = test_module(client) return_results(result) # # labels-resource # elif demisto.command() == "dspm-list-labels": return_results(get_list_of_labels(client)) # # risk-resource # elif demisto.command() == "dspm-list-risk-findings": return_results(dspm_list_risk_findings_command(client, demisto.args())) elif demisto.command() == "dspm-get-risk-finding-by-id": return_results(get_risk_finding_by_id(client, demisto.args())) elif demisto.command() == "dspm-update-risk-finding-status": return_results(update_risk_finding_status(client, demisto.args())) # # asset-resource # elif demisto.command() == "dspm-list-assets": return_results(dspm_list_assets_command(client, demisto.args())) elif demisto.command() == "dspm-get-asset-details": return_results(get_asset_details(client, demisto.args())) # # classification-resource # elif demisto.command() == "dspm-get-data-types": return_results(get_data_types(client)) elif demisto.command() == "dspm-get-asset-files-by-id": return_results(get_asset_files_by_id(client, demisto.args())) elif demisto.command() == "dspm-get-list-of-asset-fields-by-id": return_results(dspm_get_list_of_asset_fields_command(client, demisto.args())) # # data-type-findings-resource # elif demisto.command() == "dspm-list-data-types-findings": return_results(dspm_list_data_types_findings_command(client, demisto.args())) # # alert-resource # elif demisto.command() == "dspm-update-alert-status": return_results(update_dspm_alert_status(client, demisto.args())) elif demisto.command() == "dspm-list-alerts": return_results(dspm_list_alerts_command(client, demisto.args())) except Exception as e: return_error(f"Failed to execute {demisto.command()} command.\nError:\n{str(e)}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()