Details
| ID | AWS - GuardDuty |
|---|---|
| Provider | Amazon |
| Category | IT Services |
| From Version | 5.0.0 |
| Docker Image | demisto/boto3py3:1.0.0.10221838 |
| Supported Modules | Agentix XSIAM |
README
Amazon Web Services Guard Duty Service (gd)
Use this integration to detect and manage threats to your AWS system. We recommend that you use roles that have the following
built-in AWS policies:
- AmazonGuardDutyFullAccess
- AmazonGuardDutyReadOnlyAccess
For detailed instructions about setting up authentication, see: AWS Integrations - Authentication.
Prerequisites
It is important that you familiarize yourself with and complete all steps detailed in
the Amazon AWS Integrations Configuration Guide
Some changes have been made that might affect your existing content.
If you are upgrading from a previous of this integration, see Breaking Changes.
Configure AWS - GuardDuty in Cortex
| Parameter | Description | Required |
|---|---|---|
| AWS Default Region | The AWS Region for this instance of the integration. For example, us-west-2 | True |
| Role Arn | The Amazon Resource Name (ARN) role used for EC2 instance authentication. If this is used, an access key and secret key are not required. | False |
| Fetch incidents | False | |
| Incident type | Incident type | False |
| Role Session Name | A descriptive name for the assumed role session. For example, xsiam-IAM.integration-Role_SESSION | False |
| Role Session Duration | The maximum length of each session in seconds. Default: 900 seconds. The Cortex XSOAR integration will have the permissions assigned only when the session is initiated and for the defined duration. | False |
| Access Key | The access key ID used for authentication, that was configured during IAM user configuration. If this is used, Role ARN is not required. | False |
| Secret Key | The secret key used for authentication, that was configured during IAM user configuration. If this is used, Role ARN is not required. | False |
| Timeout | The time in seconds until a timeout exception is reached. You can specify just the read timeout (for example 60) or also the connect timeout followed after a comma (for example 60,10). If a connect timeout is not specified, a default of 10 second will be used. | False |
| Retries | The maximum number of retry attempts when connection or throttling errors are encountered. Set to 0 to disable retries. The default value is 5 and the limit is 10. Note: Increasing the number of retries will increase the execution time. | False |
| How many incidents to fetch each time | Default 10 |
False |
| First fetch timestamp | First fetch query <number> <time unit>, e.g., 7 days. Default 3 days |
False |
| Guard Duty Severity level | The severity level or higher of findings to be fetched: Low, Medium, or High. For example, if you set the severity level to Medium, only findings with severity level Medium or High will be fetched. | False |
| Archive findings After Fetch | You can set whether findings that are fetched will be moved to the GuardDuty archive. | False |
| Incidents Fetch Interval | Time interval for fetching incidents. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False |
Fetched Incidents Data
- The integration fetches newly created Guard DutyFindings.
Each integration instance can fetch findings from a single AWS Region. - Each region can have a maximum of 1,000 member accounts that are linked to a guard duty master account. For more information see
the Amazon GuardDuty documentation. - You can set the severity level of the findings to be fetched. “Low”, “Medium”, “High”. For example, if you set the severity
level to “Medium”, the integration will only fetch findings with severity level of Medium and higher.
Commands
You can execute these commands from the 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.
aws-gd-create-detector
Create an AWS Guard Duty Detector on the integration instance specified aws account.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:CreateDetector
Base Command
aws-gd-create-detector
Input
| Argument Name | Description | Required |
|---|---|---|
| enabled | A boolean value that specifies whether the detector is to be enabled. Possible values are: True, False. Default is True. | Required |
| enableS3Logs | The status of S3 data event logs as a data source. Possible values are: True, False. | Optional |
| enableKubernetesLogs | The status of Kubernetes audit logs as a data source. Possible values are: True, False. | Optional |
| ebsVolumesMalwareProtection | Describes the configuration for scanning EBS volumes as a data source. Possible values are: True, False. | Optional |
| findingFrequency | Specifies how frequently updated findings are exported. Possible values are: Fifteen Minutes, One Hour, Six Hours. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.DetectorId | string | The unique ID of the created detector. |
Command Example
!aws-gd-create-detector enabled=True region=eu-west-2
aws-gd-delete-detector
Deletes a Amazon GuardDuty detector specified by the detector ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:DeleteDetector
Base Command
aws-gd-delete-detector
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The unique ID that specifies the detector that you want to delete. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-delete-detector detectorId=38b1235ed3fe245279cd0c8e235db0715ac5561eb
aws-gd-get-detector
Retrieves an Amazon GuardDuty detector specified by the detectorId.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:GetDetector
Base Command
aws-gd-get-detector
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The unique ID of the detector that you want to retrieve. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.DetectorId | string | The unique ID of the created detector. |
| AWS.GuardDuty.Detectors.CreatedAt | string | The first time a resource was created. |
| AWS.GuardDuty.Detectors.ServiceRole | string | Customer serviceRole name or ARN for accessing customer resources. |
| AWS.GuardDuty.Detectors.Status | string | The status of detector. |
| AWS.GuardDuty.Detectors.UpdatedAt | string | The time a resource was last updated. |
| AWS.GuardDuty.Detectors.CloudTrailStatus | string | Describes whether CloudTrail is enabled as a data source for the detector. |
| AWS.GuardDuty.Detectors.DNSLogsStatus | string | Denotes whether DNS logs are enabled as a data source. |
| AWS.GuardDuty.Detectors.FlowLogsStatus | string | Denotes whether VPC flow logs are enabled as a data source. |
| AWS.GuardDuty.Detectors.S3LogsStatus | string | Describes whether S3 data event logs are automatically enabled for new members of the organization. |
| AWS.GuardDuty.Detectors.KubernetesAuditLogsStatus | string | Describes whether Kubernetes audit logs are enabled as a data source. |
| AWS.GuardDuty.Detectors.MalwareProtectionStatus | string | Describes whether scanning EBS volumes is enabled as a data source. |
| AWS.GuardDuty.Detectors.MalwareProtectionReason | string | Specifies the reason why scanning EBS volumes (Malware Protection) was not enabled as a data source. |
| AWS.GuardDuty.Detectors.Tags | string | The tags of the detector resource. |
Command Example
!aws-gd-get-detector detectorId=38b1ed3fe279fdascd0c8edb071dsf5ac5561eb region=eu-west-2
aws-gd-update-detector
Updates an Amazon GuardDuty detector specified by the detectorId.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:UpdateDetector
Base Command
aws-gd-update-detector
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The unique ID of the detector that you want to update. | Required |
| enable | Updated boolean value for the detector that specifies whether the detector is enabled. Possible values are: True, False. Default is True. | Required |
| enableS3Logs | The status of S3 data event logs as a data source. Possible values are: True, False. | Optional |
| enableKubernetesLogs | The status of Kubernetes audit logs as a data source. Possible values are: True, False. | Optional |
| ebsVolumesMalwareProtection | Describes the configuration for scanning EBS volumes as data source. Possible values are: True, False. | Optional |
| findingFrequency | A value that specifies how frequently updated findings are exported. Possible values are: Fifteen Minutes, One Hour, Six Hours. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
aws-gd-update-detector detectorId=38b1ed3fe279fdascd0c8edb071dsf5ac5561eb enable=True
aws-gd-create-ip-set
A list of trusted IP addresses on allow list for secure communication with AWS infrastructure and applications.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:CreateIPSet
Base Command
aws-gd-create-ip-set
Input
| Argument Name | Description | Required |
|---|---|---|
| activate | A boolean value that indicates whether GuardDuty is to start using the uploaded IPSet. Possible values are: True, False. Default is True. | Optional |
| detectorId | The unique ID of the detector that you want to update. | Required |
| format | The format of the file that contains the IPSet. Possible values are: TXT, STIX, OTX_CSV, ALIEN_VAULT, PROOF_POINT, FIRE_EYE. | Required |
| location | The URI of the file that contains the IPSet. For example (https://s3.us-west-2.amazonaws.com/my-bucket/my-object-key). | Optional |
| name | The user friendly name to identify the IPSet. This name is displayed in all findings that are triggered by activity that involves IP addresses included in this IPSet. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.IPSet.IpSetId | unknown | The unique identifier for an IP Set. |
Command Example
!aws-gd-create-ip-set format=TXT location=https://s3.eu-central-1.amazonaws.com/test/ipset.txt activate=True detectorId=38b1ed3fe279czvasdd0c8edb0715azdsfc5561eb name=test region=eu-west-2
aws-gd-delete-ip-set
Deletes the IPSet specified by the IPSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:DeleteIPSet
Base Command
aws-gd-delete-ip-set
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose IPSet you want to delete. | Required |
| ipSetId | The unique ID that specifies the IPSet that you want to delete. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-delete-ip-set detectorId=38b1ed3fe279cd0c8edb0715ac5561eb ipSetId=7eb1f440be5931f168280b574a26d44d region=eu-west-2
aws-gd-list-detectors
Lists detectorIds of all the existing Amazon GuardDuty detector resources.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ListDetectors
Base Command
aws-gd-list-detectors
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | Number of total results to query. Default is 50. |
Optional |
| page | Specific page to query. | Optional |
| page_size | Number of total results in each page. Default is 50. |
Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.DetectorId | string | The unique identifier for a detector. |
Command Example
!aws-gd-list-detectors region=eu-west-2
aws-gd-update-ip-set
Updates the IPSet specified by the IPSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:UpdateIPSet
Base Command
aws-gd-update-ip-set
Input
| Argument Name | Description | Required |
|---|---|---|
| activate | The updated boolean value that specifies whether the IPSet is active or not. Possible values are: True, False. | Optional |
| detectorId | The detectorID that specifies the GuardDuty service whose IPSet you want to update. | Required |
| ipSetId | The unique ID that specifies the IPSet that you want to update. | Required |
| location | The updated URI of the file that contains the IPSet. For example (https://s3.us-west-2.amazonaws.com/my-bucket/my-object-key). | Optional |
| name | The user friendly name to identify the IPSet. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-update-ip-set detectorId=38b1ed3fe279cd0c8edb0715ac5561eb ipSetId=7eb1f440be5931f168280b574a26d44d activate=False region=eu-west-2
aws-gd-get-ip-set
Retrieves the IPSet specified by the IPSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:GetIPSet
Base Command
aws-gd-get-ip-set
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose IPSet you want to retrieve. | Required |
| ipSetId | The unique ID that specifies the IPSet that you want to describe. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.IPSet.IpSetId | string | The unique ID for the IPSet. |
| AWS.GuardDuty.Detectors.IPSet.Format | string | The format of the file that contains the IPSet. |
| AWS.GuardDuty.Detectors.IPSet.Location | string | The URI of the file that contains the IPSet. |
| AWS.GuardDuty.Detectors.IPSet.Name | string | he user friendly name to identify the IPSet. |
| AWS.GuardDuty.Detectors.IPSet.Status | string | The status of ipSet file uploaded. |
Command Example
!aws-gd-get-ip-set detectorId=38b1ed3fesdf279cd0c8edbdsf071sdgfac5561eb ipSetId=7eb1sdff440be5931f1682adf80b574a26d44d region=eu-west-2
aws-gd-list-ip-sets
Lists the IPSets of the GuardDuty service specified by the detector ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ListIPSet
Base Command
aws-gd-list-ip-sets
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The unique ID of the detector that you want to retrieve. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
| limit | Number of total results to query. Default is 50. |
Optional |
| page | Specific page to query. | Optional |
| page_size | Number of total results in each page. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.IPSet.IpSetId | unknown | The unique identifier for an IP Set |
Command Example
!aws-gd-list-ip-sets detectorId=38b1ed3fesdf279cd0c8edbdsf071sdgfac5561eb region=eu-west-2
aws-gd-create-threatintel-set
Create a new ThreatIntelSet. ThreatIntelSets consist of known malicious IP addresses. GuardDuty generates findings based on
ThreatIntelSets.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:CreateThreatIntelSet
Base Command
aws-gd-create-threatintel-set
Input
| Argument Name | Description | Required |
|---|---|---|
| activate | A boolean value that indicates whether GuardDuty is to start using the uploaded ThreatIntelSet. Possible values are: True, False. Default is True. | Required |
| detectorId | The unique ID of the detector that you want to update. | Required |
| format | The format of the file that contains the ThreatIntelSet. Possible values are: TXT, STIX, OTX_CSV, ALIEN_VAULT, PROOF_POINT, FIRE_EYE. | Required |
| location | The URI of the file that contains the ThreatIntelSet. For example (https://s3.us-west-2.amazonaws.com/my-bucket/my-object-key). | Required |
| name | A user-friendly ThreatIntelSet name that is displayed in all finding generated by activity that involves IP addresses included in this ThreatIntelSet. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.ThreatIntelSet.ThreatIntelSetId | string | The unique identifier for an threat intel set. |
Command Example
!aws-gd-create-threatintel-set format=TXT location=https://s3.eu-central-1.amazonaws.com/test/threatintel.txt activate=True detectorId=38b1ed3fe279czvasdd0c8edb0715azdsfc5561eb name=test region=eu-west-2
aws-gd-delete-threatintel-set
Deletes ThreatIntelSet specified by the ThreatIntelSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:DeleteThreatIntelSet
Base Command
aws-gd-delete-threatintel-set
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose ThreatIntelSet you want to delete. | Required |
| threatIntelSetId | The unique ID that specifies the ThreatIntelSet that you want to delete. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-delete-threatintel-set detectorId=38b1ed3fe279cd0c8edb0715ac5561eb threatIntelSetId=7eb1f440be5931f168280b574a26d44d region=eu-west-2
aws-gd-get-threatintel-set
Retrieves the ThreatIntelSet that is specified by the ThreatIntelSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:GetThreatIntelSet
Base Command
aws-gd-get-threatintel-set
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose ThreatIntelSet you want to describe. | Required |
| threatIntelSetId | The unique ID that specifies the ThreatIntelSet that you want to describe. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.ThreatIntelSet.ThreatIntelSetId | string | The unique ID that specifies the ThreatIntelSet. |
| AWS.GuardDuty.Detectors.ThreatIntelSet.Format | string | The format of the threatIntelSet. |
| AWS.GuardDuty.Detectors.ThreatIntelSet.Location | string | The URI of the file that contains the ThreatIntelSet. |
| AWS.GuardDuty.Detectors.ThreatIntelSet.Name | string | A user-friendly ThreatIntelSet name. |
| AWS.GuardDuty.Detectors.ThreatIntelSet.Status | string | The status of threatIntelSet file uploaded. |
Command Example
!aws-gd-get-threatintel-set detectorId=38b1ed3fe279cd0c8edb0715ac5561eb threatIntelSetId=7eb1f440be5931f168280b574a26d44d region=eu-west-2
aws-gd-list-threatintel-sets
Lists the ThreatIntelSets of the GuardDuty service specified by the detector ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ListThreatIntelSet
Base Command
aws-gd-list-threatintel-sets
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose ThreatIntelSets you want to list. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
| limit | Number of total results to query. Default is 50. |
Optional |
| page | Specific page to query. | Optional |
| page_size | Number of total results in each page. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Detectors.ThreatIntelSet.ThreatIntelSetId | string | The unique identifier for an threat intel set |
Command Example
!aws-gd-list-threatintel-sets detectorId=38b1ed3fe279cd0c8edb0715ac5561eb region=eu-west-2
aws-gd-update-threatintel-set
Updates the ThreatIntelSet specified by ThreatIntelSet ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:UpdateThreatIntelSet
Base Command
aws-gd-update-threatintel-set
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The detectorID that specifies the GuardDuty service whose ThreatIntelSet you want to update. | Required |
| threatIntelSetId | The unique ID that specifies the ThreatIntelSet that you want to update. | Optional |
| activate | The updated boolean value that specifies whether the ThreatIntelSet is active or not. Possible values are: True, False. | Optional |
| location | The updated URI of the file that contains the ThreatIntelSet. For example (https://s3.us-west-2.amazonaws.com/my-bucket/my-object-key). | Optional |
| name | The user-friendly ThreatIntelSet name. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-update-threatintel-set detectorId=38b1ed3fe279cd0c8edb0715ac5561eb threatIntelSetId=7eb1f440be5931f168280b574a26d44d activate=False region=eu-west-2
aws-gd-list-findings
Lists Amazon GuardDuty findings for the specified detector ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ListFindings
Base Command
aws-gd-list-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose findings you want to list. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
| limit | Number of total results to query. Default is 50. |
Optional |
| page | Specific page to query. | Optional |
| page_size | Number of total results in each page. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Findings.FindingId | string | The unique identifier for the Finding |
Command Example
!aws-gd-list-findings detectorId=38b1ed3fe279cd0c8edb0715ac5561eb region=eu-west-2
aws-gd-get-findings
Describes Amazon GuardDuty findings specified by finding IDs.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:GetFindings
Base Command
aws-gd-get-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose findings you want to retrieve. | Required |
| findingIds | IDs of the findings that you want to retrieve. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
| returnRawResponse | Select ‘true’ to save all fields from the response to the context. Otherwise, complex fields will be stored in JSON format. Default value is False. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Findings.AccountId | string | The ID of the account in which the finding was generated. |
| AWS.GuardDuty.Findings.CreatedAt | string | The time and date when the finding was created. |
| AWS.GuardDuty.Findings.Description | string | The description of the finding. |
| AWS.GuardDuty.Findings.Region | string | The region where the finding was generated. |
| AWS.GuardDuty.Findings.Id | string | The ID of the finding. |
| AWS.GuardDuty.Findings.Title | string | The title of the finding. |
| AWS.GuardDuty.Findings.Severity | string | The severity of the finding. |
| AWS.GuardDuty.Findings.Type | string | The type of finding. |
| AWS.GuardDuty.Findings.UpdatedAt | string | The time and date when the finding was last updated. |
| AWS.GuardDuty.Findings.Arn | string | The ARN of the finding. |
| AWS.GuardDuty.Findings.Confidence | string | The confidence score for the finding. |
| AWS.GuardDuty.Findings.Partition | string | The partition associated with the finding. |
| AWS.GuardDuty.Findings.ResourceType | string | The type of Amazon Web Services resource. |
| AWS.GuardDuty.Findings.SchemaVersion | string | The version of the schema used for the finding. |
| AWS.GuardDuty.Findings.Service | string | Contains additional information about the generated finding. |
| AWS.GuardDuty.Findings.Resource.AccessKeyDetails | string | The IAM access key details (IAM user information) of a user that engaged in the activity that prompted GuardDuty to generate a finding. |
| AWS.GuardDuty.Findings.Resource.InstanceDetails | string | The information about the EC2 instance associated with the activity that prompted GuardDuty to generate a finding. |
| AWS.GuardDuty.Findings.Resource.EksClusterDetails | string | Details about the EKS cluster involved in a Kubernetes finding. |
| AWS.GuardDuty.Findings.Resource.KubernetesDetails | string | Details about the Kubernetes user and workload involved in a Kubernetes finding. |
| AWS.GuardDuty.Findings.Resource.EbsVolumeDetails | string | Contains a list of scanned and skipped EBS volumes with details. |
| AWS.GuardDuty.Findings.Resource.EcsClusterDetails | string | Contains information about the details of the ECS Cluster. |
| AWS.GuardDuty.Findings.Resource.ContainerDetails | string | Details of a container. |
| AWS.GuardDuty.Findings.Resource.S3BucketDetails | string | Contains information on the S3 bucket. |
Command Example
!aws-gd-get-findings detectorIds=4f1fc7cd7dsg26sdf4328d8dc813 findingIds=96b1ac608sdf00e5183c3dds115c36aac328b,0ab180f5801sdg954418f3806c2a45282c9
aws-gd-create-sample-findings
Generates example findings of types specified by the list of finding types. If ‘NULL’ is specified for findingTypes, the API
generates example findings of all supported finding types.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:CreateSampleFindings
Base Command
aws-gd-create-sample-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector to create sample findings for. | Required |
| findingTypes | Types of sample findings that you want to generate. Separated by comma. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-create-sample-findings detectorId=4f1fc7cd7dsg2adf6sdf4328d8dc813 findingTypes=NULL region=eu-central-1
aws-gd-archive-findings
Archives Amazon GuardDuty findings specified by the list of finding IDs.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ArchiveFindings
Base Command
aws-gd-archive-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose findings you want to archive. | Required |
| findingIds | IDs of the findings that you want to archive. Separated by comma. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-archive-findings detectorIds=4f1fc7cd7dsg26sdf4328d8dc813 findingIds=96b1ac608sdf00e5183c3dds115c36aac328b,0ab180f5801sdg954418f3806c2a45282c9
aws-gd-unarchive-findings
Unarchives Amazon GuardDuty findings specified by the list of finding IDs.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:UnarchiveFindings
Base Command
aws-gd-unarchive-findings
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose findings you want to unarchive. | Required |
| findingIds | IDs of the findings that you want to unarchive. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-unarchive-findings detectorIds=4f1fc7cd7dsg26sdf4328d8dc813 findingIds=96b1ac608sdf00e5183c3dds115c36aac328b,0ab180f5801sdg954418f3806c2a45282c9
aws-gd-update-findings-feedback
Marks specified Amazon GuardDuty findings as useful or not useful.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:UpdateFindingsFeedback
Base Command
aws-gd-update-findings-feedback
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose findings you want to mark as useful or not useful. | Required |
| findingIds | IDs of the findings that you want to mark as useful or not useful. | Optional |
| comments | Additional feedback about the GuardDuty findings. | Optional |
| feedback | Specify whether the finding was useful or not. Possible values are: USEFUL, NOT_USEFUL. | Optional |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
There is no context output for this command.
Command Example
!aws-gd-update-findings-feedback detectorIds=4f1fc7cd7dsg26sdf4328d8dc813 findingIds=96b1ac608sdf00e5183c3dds115c36aac328b comments=Good Job feedback=USEFUL
aws-gd-list-members
Describes Amazon GuardDuty members for the specified detector ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:ListMembers
Base Command
aws-gd-list-members
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose members you want to retrieve. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
| limit | Number of total results to query. Default is 50. |
Optional |
| page | Specific page to query. | Optional |
| page_size | Number of total results in each page. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Members.AccountId | string | The unique account ID of the member. |
| AWS.GuardDuty.Members.DetectorId | string | The unique detector ID of the member. |
| AWS.GuardDuty.Members.MasterId | string | The unique detector ID of the master. |
| AWS.GuardDuty.Members.Email | string | The email of the member. |
| AWS.GuardDuty.Members.RelationshipStatus | string | The relationship status of member. |
| AWS.GuardDuty.Members.InvitedAt | string | The first time a member was invited. |
| AWS.GuardDuty.Members.UpdatedAt | string | The time a member was last updated. |
Command Example
!aws-gd-list-members detectorIds=4f1fc7cd7dsg26sdf4328d8dc813
aws-gd-get-members
Describes Amazon GuardDuty members for the specified detector ID & account ID.
AWS IAM Policy Permission
Effect: Allow
Action: guardduty:GetMembers
Base Command
aws-gd-get-members
Input
| Argument Name | Description | Required |
|---|---|---|
| detectorId | The ID of the detector that specifies the GuardDuty service whose members you want to retrieve. | Required |
| accountIds | The ID of the account that specifies the GuardDuty service whose details you want to retrieve. | Required |
| region | The AWS Region, if not specified the default region will be used. | Optional |
| roleArn | The Amazon Resource Name (ARN) of the role to assume. | Optional |
| roleSessionName | An identifier for the assumed role session. | Optional |
| roleSessionDuration | The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum session duration setting for the role. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| AWS.GuardDuty.Members.AccountId | string | The unique account ID of the member. |
| AWS.GuardDuty.Members.DetectorId | string | The unique detector ID of the member. |
| AWS.GuardDuty.Members.MasterId | string | The unique detector ID of the master. |
| AWS.GuardDuty.Members.Email | string | The email of the member. |
| AWS.GuardDuty.Members.RelationshipStatus | string | The relationship status of member. |
| AWS.GuardDuty.Members.InvitedAt | string | The first time a member was invited. |
| AWS.GuardDuty.Members.UpdatedAt | string | The time a member was last updated. |
Command Example
!aws-gd-get-members detectorIds=4f1fc7cd7dsg26sdf4328d8dc813 accountIds=1f3fc2cd1dag26sdf4338d8aa813
Breaking changes from the previous version of this integration - AWS-GuardDuty
The following sections list the changes in this version.
Commands
Fetch incidents command - Findings that are fetched are no longer moved automatically to the GuardDuty archive.
Parameters
The following parameters were added in this version:
- How many incidents to fetch each time
- First fetch timestamp
- Archive findings After Fetch
Configuration parameters
defaultRegion— AWS Default Region (required)roleArn— Role ArnisFetch— Fetch incidentsincidentType— Incident typeroleSessionName— Role Session NamesessionDuration— Role Session Durationcredentials— Access Keyaccess_key— Access Keysecret_key— Secret Keytimeout— Timeoutretries— Retriesendpoint_url— PrivateLink service URL.sts_endpoint_url— STS PrivateLink URL.sts_regional_endpoint— AWS STS Regional Endpointsfetch_limit— How many incidents to fetch each timefirst_fetch_time— First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year)gs_severity— Guard Duty Severity levelis_archive— Archive findings After FetchincidentFetchInterval— Incidents Fetch Intervalinsecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (23)
-
aws-gd-archive-findingsArchives Amazon GuardDuty findings specified by the list of finding IDs.
-
aws-gd-create-detectorCreate an AWS Guard Duty Detector on the integration instance specified aws account.
-
aws-gd-create-ip-setA list of trusted IP addresses on allow list for secure communication with AWS infrastructure and applications.
-
aws-gd-create-sample-findingsGenerates example findings of types specified by the list of finding types. If 'NULL' is specified for findingTypes, the API generates example findings of all supported finding types.
-
aws-gd-create-threatintel-setCreate a new ThreatIntelSet. ThreatIntelSets consist of known malicious IP addresses. GuardDuty generates findings based on ThreatIntelSets.
-
aws-gd-delete-detectorDeletes a Amazon GuardDuty detector specified by the detector ID.
-
aws-gd-delete-ip-setDeletes the IPSet specified by the IPSet ID.
-
aws-gd-delete-threatintel-setDeletes ThreatIntelSet specified by the ThreatIntelSet ID.
-
aws-gd-get-detectorRetrieves an Amazon GuardDuty detector specified by the detectorId.
-
aws-gd-get-findingsDescribes Amazon GuardDuty findings specified by finding IDs.
-
aws-gd-get-ip-setRetrieves the IPSet specified by the IPSet ID.
-
aws-gd-get-membersDescribes Amazon GuardDuty members for the specified detector ID & account ID.
-
aws-gd-get-threatintel-setRetrieves the ThreatIntelSet that is specified by the ThreatIntelSet ID.
-
aws-gd-list-detectorsLists detectorIds of all the existing Amazon GuardDuty detector resources.
-
aws-gd-list-findingsLists Amazon GuardDuty findings for the specified detector ID.
-
aws-gd-list-ip-setsLists the IPSets of the GuardDuty service specified by the detector ID.
-
aws-gd-list-membersDescribes Amazon GuardDuty members for the specified detector ID.
-
aws-gd-list-threatintel-setsLists the ThreatIntelSets of the GuardDuty service specified by the detector ID.
-
aws-gd-unarchive-findingsUnarchives Amazon GuardDuty findings specified by the list of finding IDs.
-
aws-gd-update-detectorUpdates an Amazon GuardDuty detector specified by the detectorId.
-
aws-gd-update-findings-feedbackMarks specified Amazon GuardDuty findings as useful or not useful.
-
aws-gd-update-ip-setUpdates the IPSet specified by the IPSet ID.
-
aws-gd-update-threatintel-setUpdates the ThreatIntelSet specified by ThreatIntelSet ID.
import json from collections import defaultdict from datetime import date, datetime from typing import TYPE_CHECKING import demistomock as demisto # noqa: F401 from AWSApiModule import * # noqa: E402 from CommonServerPython import * # noqa: F401 # The following import are used only for type hints and autocomplete. # It is not used at runtime, and not exist in the docker image. if TYPE_CHECKING: from mypy_boto3_guardduty import GuardDutyClient from mypy_boto3_guardduty.type_defs import ConditionTypeDef, FindingTypeDef """ CONSTANTS """ SERVICE = "guardduty" FINDING_FREQUENCY = {"Fifteen Minutes": "FIFTEEN_MINUTES", "One Hour": "ONE_HOUR", "Six Hours": "SIX_HOURS"} DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" MAX_RESULTS_RESPONSE = 50 class DatetimeEncoder(json.JSONEncoder): def default(self, obj: Any): # pylint: disable=E0202 if isinstance(obj, datetime): return obj.strftime("%Y-%m-%dT%H:%M:%S") elif isinstance(obj, date): # pylint: disable=E0602 return obj.strftime("%Y-%m-%d") # Let the base class default method raise the TypeError return json.JSONEncoder.default(self, obj) def create_detector(client: "GuardDutyClient", args: dict) -> CommandResults: """ Creates a single Amazon GuardDuty detector. """ kwargs = {"Enable": argToBoolean(args.get("enabled", False))} if args.get("findingFrequency"): kwargs["FindingPublishingFrequency"] = FINDING_FREQUENCY[args["findingFrequency"]] get_dataSources = {} if args.get("enableKubernetesLogs"): get_dataSources.update({"Kubernetes": {"AuditLogs": {"Enable": argToBoolean(args["enableKubernetesLogs"])}}}) if args.get("ebsVolumesMalwareProtection"): get_dataSources.update( { "MalwareProtection": { "ScanEc2InstanceWithFindings": {"EbsVolumes": argToBoolean(args["ebsVolumesMalwareProtection"])} } } ) if args.get("enableS3Logs"): get_dataSources.update({"S3Logs": {"Enable": argToBoolean(args["enableS3Logs"])}}) if get_dataSources: kwargs["DataSources"] = get_dataSources response = client.create_detector(**kwargs) data = {"DetectorId": response["DetectorId"]} readable_output = ( tableToMarkdown("AWS GuardDuty Detectors - detector created successfully", data) if data else "No result were found" ) return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors", outputs_key_field="DetectorId" ) def delete_detector(client: "GuardDutyClient", args: dict): response = client.delete_detector(DetectorId=args.get("detectorId", "")) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The Detector {args.get('detectorId')} has been deleted" else: raise Exception(f"The Detector {args.get('detectorId')} failed to delete.") def get_detector(client: "GuardDutyClient", args: dict) -> CommandResults: """ Retrieves an Amazon GuardDuty detector specified by the detectorId. """ response = client.get_detector(DetectorId=args.get("detectorId", "")) data = { "DetectorId": args.get("detectorId"), "CreatedAt": response.get("CreatedAt"), "ServiceRole": response.get("ServiceRole"), "Status": response.get("Status"), "UpdatedAt": response.get("UpdatedAt"), "CloudTrailStatus": demisto.get(response, "DataSources.CloudTrail.Status"), "DNSLogsStatus": demisto.get(response, "DataSources.DNSLogs.Status"), "FlowLogsStatus": demisto.get(response, "DataSources.FlowLogs.Status"), "S3LogsStatus": demisto.get(response, "DataSources.S3Logs.Status"), "KubernetesAuditLogsStatus": demisto.get(response, "DataSources.Kubernetes.AuditLogs.Status"), "MalwareProtectionStatus": demisto.get( response, "DataSources.MalwareProtection.ScanEc2InstanceWithFindings.EbsVolumes.Status" ), "MalwareProtectionReason": demisto.get( response, "DataSources.MalwareProtection.ScanEc2InstanceWithFindings.EbsVolumes.Reason" ), "Tags": response.get("Tags"), } readable_output = tableToMarkdown("AWS GuardDuty Detectors", data, removeNull=True) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors", outputs_key_field="DetectorId" ) def update_detector(client: "GuardDutyClient", args: dict) -> str: """ Updates the Amazon GuardDuty detector specified by the detectorId. """ kwargs = {"Enable": argToBoolean(args.get("enable", False)), "DetectorId": args.get("detectorId")} if args.get("findingFrequency"): kwargs["FindingPublishingFrequency"] = FINDING_FREQUENCY[args["findingFrequency"]] get_dataSources = {} if args.get("enableKubernetesLogs"): get_dataSources.update({"Kubernetes": {"AuditLogs": {"Enable": argToBoolean(args["enableKubernetesLogs"])}}}) if args.get("ebsVolumesMalwareProtection"): get_dataSources.update( { "MalwareProtection": { "ScanEc2InstanceWithFindings": {"EbsVolumes": argToBoolean(args["ebsVolumesMalwareProtection"])} } } ) if args.get("enableS3Logs"): get_dataSources.update({"S3Logs": {"Enable": argToBoolean(args["enableS3Logs"])}}) if get_dataSources: kwargs["DataSources"] = get_dataSources response = client.update_detector(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The Detector {args.get('detectorId')} has been updated successfully" else: raise Exception(f"Detector {args.get('detectorId')} failed to update. Response was: {response}") def list_detectors(client: "GuardDutyClient", args: dict) -> CommandResults: limit, page_size, page = get_pagination_args(args) paginator = client.get_paginator("list_detectors") response_iterator = paginator.paginate( PaginationConfig={ "MaxItems": limit, "PageSize": page_size, } ) data = [] for i, page_response in enumerate(response_iterator): if page is None or (page - 1) == i: for detector in page_response["DetectorIds"]: data.append({"DetectorId": detector}) if page: break readable_output = tableToMarkdown("AWS GuardDuty Detectors", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors", outputs_key_field="DetectorId" ) def create_ip_set(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId")} if args.get("activate") is not None: kwargs.update({"Activate": args.get("activate") == "True"}) if args.get("format") is not None: kwargs.update({"Format": args.get("format")}) if args.get("location") is not None: kwargs.update({"Location": args.get("location")}) if args.get("name") is not None: kwargs.update({"Name": args.get("name")}) response = client.create_ip_set(**kwargs) data = {"DetectorId": args.get("detectorId"), "IpSetId": response["IpSetId"]} readable_output = tableToMarkdown("AWS GuardDuty IPSets", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.IPSet", outputs_key_field="IpSetId" ) def delete_ip_set(client: "GuardDutyClient", args: dict): response = client.delete_ip_set(DetectorId=args.get("detectorId", ""), IpSetId=args.get("ipSetId", "")) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The IPSet {args.get('ipSetId')} has been deleted from Detector {args.get('detectorId')}" else: raise Exception(f"Failed to delete ip set {args.get('ipSetId')} . Response was: {response}") def update_ip_set(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId"), "IpSetId": args.get("ipSetId")} if args.get("activate"): kwargs.update({"Activate": args.get("activate") == "True"}) if args.get("location"): kwargs.update({"Location": args.get("location")}) if args.get("name"): kwargs.update({"Name": args.get("name")}) response = client.update_ip_set(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The IPSet {args.get('ipSetId')} has been Updated" else: raise Exception(f"Failed updating ip set {args.get('ipSetId')} . Response was: {response}") def get_ip_set(client: "GuardDutyClient", args: dict): response = client.get_ip_set(DetectorId=args.get("detectorId", ""), IpSetId=args.get("ipSetId", "")) data = { "DetectorId": args.get("detectorId"), "IpSetId": args.get("ipSetId"), "Format": response["Format"], "Location": response["Location"], "Name": response["Name"], "Status": response["Status"], } readable_output = tableToMarkdown("AWS GuardDuty IPSets", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.IPSet", outputs_key_field="IpSetId" ) def list_ip_sets(client: "GuardDutyClient", args: dict) -> CommandResults: limit, page_size, page = get_pagination_args(args) paginator = client.get_paginator("list_ip_sets") response_iterator = paginator.paginate( DetectorId=args.get("detectorId", ""), PaginationConfig={ "MaxItems": limit, "PageSize": page_size, }, ) data = [] data.append({"DetectorId": args.get("detectorId")}) for i, page_response in enumerate(response_iterator): if page is None or (page - 1) == i: for ipSet in page_response["IpSetIds"]: data.append({"IpSetId": ipSet}) if page: break readable_output = tableToMarkdown("AWS GuardDuty IPSets", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.IPSet", outputs_key_field="IpSetId" ) def create_threat_intel_set(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId")} if args.get("activate") is not None: kwargs.update({"Activate": args.get("activate") == "True"}) if args.get("format") is not None: kwargs.update({"Format": args.get("format")}) if args.get("location") is not None: kwargs.update({"Location": args.get("location")}) if args.get("name") is not None: kwargs.update({"Name": args.get("name")}) response = client.create_threat_intel_set(**kwargs) data = {"DetectorId": args.get("detectorId"), "ThreatIntelSetId": response["ThreatIntelSetId"]} readable_output = tableToMarkdown("AWS GuardDuty ThreatIntel Set", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.ThreatIntelSet", outputs_key_field="ThreatIntelSetId", ) def delete_threat_intel_set(client: "GuardDutyClient", args: dict): response = client.delete_threat_intel_set( DetectorId=args.get("detectorId", ""), ThreatIntelSetId=args.get("threatIntelSetId", "") ) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The ThreatIntel Set {args.get('threatIntelSetId')} has been deleted from Detector {args.get('detectorId')}" else: raise Exception(f"Failed to delete ThreatIntel set {args.get('threatIntelSetId')} . Response was: {response}") def get_threat_intel_set(client: "GuardDutyClient", args: dict): response = client.get_threat_intel_set( DetectorId=args.get("detectorId", ""), ThreatIntelSetId=args.get("threatIntelSetId", "") ) data = { "DetectorId": args.get("detectorId"), "ThreatIntelSetId": args.get("threatIntelSetId"), "Format": response["Format"], "Location": response["Location"], "Name": response["Name"], "Status": response["Status"], } readable_output = tableToMarkdown("AWS GuardDuty ThreatIntel Set", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.ThreatIntelSet", outputs_key_field="ThreatIntelSetId", ) def list_threat_intel_sets(client: "GuardDutyClient", args: dict) -> CommandResults: limit, page_size, page = get_pagination_args(args) paginator = client.get_paginator("list_threat_intel_sets") response_iterator = paginator.paginate( DetectorId=args.get("detectorId", ""), PaginationConfig={ "MaxItems": limit, "PageSize": page_size, }, ) data = [] data.append({"DetectorId": args.get("detectorId")}) for i, page_response in enumerate(response_iterator): if page is None or (page - 1) == i: for threatIntelSet in page_response["ThreatIntelSetIds"]: data.append({"ThreatIntelSetId": threatIntelSet}) if page: break readable_output = tableToMarkdown("AWS GuardDuty ThreatIntel Sets", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Detectors.ThreatIntelSet", outputs_key_field="ThreatIntelSetId", ) def update_threat_intel_set(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId"), "ThreatIntelSetId": args.get("threatIntelSetId")} if args.get("activate"): kwargs.update({"Activate": args.get("activate") == "True"}) if args.get("location"): kwargs.update({"Location": args.get("location")}) if args.get("name"): kwargs.update({"Name": args.get("name")}) response = client.update_threat_intel_set(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return f"The ThreatIntel set {args.get('threatIntelSetId')} has been updated" else: raise Exception(f"Failed updating ThreatIntel set {args.get('threatIntelSetId')}. Response was: {response}") def severity_mapping(severity: Optional[float]) -> Optional[int]: demisto_severity = None if severity: if severity <= 3.9: demisto_severity = 1 elif 4 <= severity <= 6.9: demisto_severity = 2 elif 7 <= severity <= 8.9: demisto_severity = 3 else: demisto_severity = 0 return demisto_severity def gd_severity_mapping(severity_list: List[str]): if "Low" in severity_list: gd_severity = 1 elif "Medium" in severity_list: gd_severity = 4 elif "High" in severity_list: gd_severity = 7 else: gd_severity = 1 return gd_severity def list_findings(client: "GuardDutyClient", args: dict) -> CommandResults: limit, page_size, page = get_pagination_args(args) paginator = client.get_paginator("list_findings") response_iterator = paginator.paginate( DetectorId=args.get("detectorId", ""), PaginationConfig={ "MaxItems": limit, "PageSize": page_size, }, ) data = [] for i, page_response in enumerate(response_iterator): if page is None or (page - 1) == i: for finding in page_response["FindingIds"]: data.append({"FindingId": finding}) if page: break readable_output = tableToMarkdown("AWS GuardDuty Findings", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Findings", outputs_key_field="" ) def get_pagination_args(args: dict) -> tuple[int, int, Optional[int]]: """ Gets and validates pagination arguments. :param args: The command arguments (page, page_size or limit) :return: limit, page_size, page after validation and convert """ # Automatic Pagination limit = arg_to_number(args.get("limit")) or MAX_RESULTS_RESPONSE # Manual Pagination page = arg_to_number(args.get("page")) if page is not None and page <= 0: raise DemistoException("page argument must be greater than 0") page_size = arg_to_number(args.get("page_size")) or MAX_RESULTS_RESPONSE if not 0 < page_size <= MAX_RESULTS_RESPONSE: raise DemistoException(f"page_size argument must be between 1 to {MAX_RESULTS_RESPONSE}") if page: limit = page * page_size return limit, page_size, page def parse_finding(finding: "FindingTypeDef") -> Dict[str, Any]: """ Parse the finding data to output, context format :param finding: Contains information about the finding, which is generated when abnormal or suspicious activity is detected. :return: parsed_finding """ parsed_finding: dict = {} parsed_finding["AccountId"] = finding.get("AccountId") parsed_finding["CreatedAt"] = finding.get("CreatedAt") parsed_finding["Description"] = finding.get("Description") parsed_finding["Region"] = finding.get("Region") parsed_finding["Id"] = finding.get("Id") parsed_finding["Title"] = finding.get("Title") parsed_finding["Type"] = finding.get("Type") parsed_finding["Severity"] = severity_mapping(finding.get("Severity")) parsed_finding["UpdatedAt"] = finding.get("UpdatedAt") parsed_finding["Arn"] = finding.get("Arn") parsed_finding["Confidence"] = finding.get("Confidence") parsed_finding["Partition"] = finding.get("Partition") parsed_finding["SchemaVersion"] = finding.get("SchemaVersion") parsed_finding["Service"] = json.dumps(finding.get("Service"), cls=DatetimeEncoder) parsed_finding["ResourceType"] = demisto.get(finding, "Resource.ResourceType") get_resource = finding.get("Resource") if get_resource: parsed_finding["Resource"] = { k: json.dumps(v, cls=DatetimeEncoder) for k, v in get_resource.items() if k != "ResourceType" } return parsed_finding def get_findings(client: "GuardDutyClient", args: dict) -> dict: return_raw_response = argToBoolean(args.get("returnRawResponse", "false")) response = client.get_findings(DetectorId=args.get("detectorId", ""), FindingIds=argToList(args.get("findingIds"))) data = [] for finding in response["Findings"]: data.append(parse_finding(finding)) output = json.dumps(response["Findings"], cls=DatetimeEncoder) raw = json.loads(output) headers = ["Id", "Title", "Description", "Type", "ResourceType", "CreatedAt", "AccountId", "Arn"] readable_output = ( tableToMarkdown("AWS GuardDuty Findings", data, removeNull=True, headers=headers) if data else "No result were found" ) return { "ContentsFormat": formats["json"], "Type": entryTypes["note"], "Contents": raw if raw else data, "ReadableContentsFormat": formats["markdown"], "HumanReadable": readable_output, "EntryContext": {"AWS.GuardDuty.Findings(val.FindingId === obj.Id)": raw if return_raw_response else data}, } def parse_incident_from_finding(finding: "FindingTypeDef") -> Dict[str, Any]: incident: dict = {} incident["name"] = finding.get("Title") incident["details"] = finding.get("Description") incident["occurred"] = finding.get("CreatedAt") incident["severity"] = severity_mapping(finding.get("Severity")) incident["rawJSON"] = json.dumps(finding, default=str) return incident def time_to_unix_epoch(date_time: datetime) -> int: """ :param date_time: The time and date in '%Y-%m-%dT%H:%M:%S.%fZ' format :return: Timestamp in Unix Epoch millisecond format example: date_time = dateparser.parse('2017-02-10 00:09:35.000000+00:00') to 1486685375000 """ return int(date_time.timestamp() * 1000) def fetch_incidents( client: "GuardDutyClient", aws_gd_severity: List[str], last_run: dict, fetch_limit: int, first_fetch_time: str, is_archive: bool, ) -> tuple[Dict[str, Any], List[dict]]: """ This function will execute each interval (default is 1 minute). Args: client (Client): "GuardDutyClient" client aws_gd_severity (List[str]): Guard Duty Severity level last_run (dict): {'latest_created_time' (string): The greatest incident created_time we fetched from last fetch, 'latest_updated_time' (string): The greatest incident updated_time we fetched from last fetch, 'last_incidents_ids' (list): The last incidents ids of the latest_created_time, 'last_next_token' (string): The value of NextToken from the previous response to continue listing data.} fetch_limit (int): Maximum numbers of incidents per fetch first_fetch_time (str): If last_fetch is None then fetch all incidents since first_fetch_time is_archive (bool): Archive findings After Fetch Returns: next_run: This will be last_run in the next fetch-incidents incidents: Incidents that will be created in Demisto """ # Get the latest_created_time, latest_updated_time, last_incidents_ids, and last_next_token if exist latest_created_time = last_run.get("latest_created_time") last_incidents_ids = last_run.get("last_incidents_ids", []) last_next_token = last_run.get("last_next_token", "") if latest_updated_time := last_run.get("latest_updated_time", ""): latest_updated_time = dateparser.parse(latest_updated_time) # Handle first time fetch if latest_created_time is None: latest_created_time = dateparser.parse(dateparser.parse(first_fetch_time).strftime(DATE_FORMAT)) # type: ignore[union-attr] else: latest_created_time = dateparser.parse(latest_created_time) response = client.list_detectors() detector = response["DetectorIds"] created_time_to_ids = defaultdict(list) created_time_to_ids[latest_created_time] = last_incidents_ids # Represents the criteria to be used in the filter for querying findings. criterion_conditions: Dict[str, ConditionTypeDef] = {} criterion_conditions["severity"] = {"Gte": gd_severity_mapping(aws_gd_severity)} if is_archive: demisto.debug("Fetching Amazon GuardDuty with Archive") criterion_conditions["service.archived"] = {"Eq": ["false"]} if not last_next_token and latest_updated_time: criterion_conditions["updatedAt"] = {"Gte": time_to_unix_epoch(latest_updated_time)} if last_incidents_ids: criterion_conditions["id"] = {"Neq": last_incidents_ids[:]} demisto.info(f"Fetching Amazon GuardDuty findings for the {detector[0]} since: {latest_created_time!s}") incidents: list[dict] = [] while True: left_to_fetch = fetch_limit - len(incidents) max_results = min(MAX_RESULTS_RESPONSE, left_to_fetch) list_findings_res = client.list_findings( DetectorId=detector[0], FindingCriteria={"Criterion": criterion_conditions}, SortCriteria={"AttributeName": "createdAt", "OrderBy": "ASC"}, MaxResults=max_results, NextToken=last_next_token, ) last_next_token = list_findings_res.get("NextToken", "") finding_ids = list_findings_res.get("FindingIds", []) get_findings_res = client.get_findings( DetectorId=detector[0], FindingIds=finding_ids, SortCriteria={"AttributeName": "createdAt", "OrderBy": "ASC"} ) for finding in get_findings_res["Findings"]: incident_created_time = dateparser.parse(finding.get("CreatedAt", "")) incident_updated_time = dateparser.parse(finding.get("UpdatedAt", "")) incident_id = finding.get("Id") # Update the latest_updated_time if not latest_updated_time or (incident_updated_time and incident_updated_time > latest_updated_time): latest_updated_time = incident_updated_time # Update last run (latest_created_time) and add incident if the incident is newer than last fetch if (incident_created_time and latest_created_time) and incident_created_time >= latest_created_time: demisto.debug( f"Added Incident with ID {incident_id}, occured: {incident_created_time!s}, " f"updated: {incident_updated_time!s}" ) latest_created_time = incident_created_time created_time_to_ids[latest_created_time].append(incident_id) incident = parse_incident_from_finding(finding) incidents.append(incident) if incidents and is_archive: # Archive findings demisto.debug(f"Archived {len(finding_ids)} findings.") client.archive_findings(DetectorId=detector[0], FindingIds=finding_ids) # if there is no next_token, or we have reached the fetch_limit -> break if not last_next_token or fetch_limit - len(incidents) == 0: demisto.debug("fetch_limit has been reached or there is no next token") break next_run = { "latest_created_time": latest_created_time.strftime(DATE_FORMAT) if latest_created_time else None, "latest_updated_time": latest_updated_time.strftime(DATE_FORMAT) if latest_updated_time else None, "last_incidents_ids": created_time_to_ids[latest_created_time], "last_next_token": last_next_token, } demisto.debug(f"{next_run=}") demisto.debug(f"fetched {len(incidents)} incidents") return next_run, incidents def create_sample_findings(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId")} if args.get("findingTypes") is not None: kwargs.update({"FindingTypes": argToList(args.get("findingTypes"))}) response = client.create_sample_findings(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return "Sample Findings were generated" else: raise Exception(f"Failed to generate findings. Response was: {response}") def archive_findings(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId")} if args.get("findingIds") is not None: kwargs.update({"FindingIds": argToList(args.get("findingIds"))}) response = client.archive_findings(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return "Findings were archived" else: raise Exception(f"Failed to archive findings. Response was: {response}") def unarchive_findings(client: "GuardDutyClient", args: dict): kwargs: dict = {"DetectorId": args.get("detectorId")} if args.get("findingIds") is not None: kwargs.update({"FindingIds": argToList(args.get("findingIds"))}) response = client.unarchive_findings(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return "Findings were unarchived" else: raise Exception(f"Failed to archive findings. Response was: {response}") def update_findings_feedback(client: "GuardDutyClient", args: dict): kwargs: dict[str, Any] = {"DetectorId": args.get("detectorId")} if args.get("findingIds") is not None: kwargs.update({"FindingIds": argToList(args.get("findingIds"))}) if args.get("comments") is not None: kwargs.update({"Comments": args.get("comments")}) if args.get("feedback") is not None: kwargs.update({"Feedback": args.get("feedback")}) response = client.update_findings_feedback(**kwargs) if response == {} or response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 200: return "Findings Feedback sent!" else: raise Exception(f"Failed to send findings feedback. Response was: {response}") def list_members(client: "GuardDutyClient", args: dict) -> CommandResults: limit, page_size, page = get_pagination_args(args) paginator = client.get_paginator("list_members") response_iterator = paginator.paginate( DetectorId=args.get("detectorId", ""), PaginationConfig={ "MaxItems": limit, "PageSize": page_size, }, ) data = [] for i, page_response in enumerate(response_iterator): if page is None or (page - 1) == i: for member in page_response["Members"]: data.append({"Member": member}) if page: break readable_output = tableToMarkdown("AWS GuardDuty Members", data) if data else "No result were found" return CommandResults( readable_output=readable_output, outputs=data, outputs_prefix="AWS.GuardDuty.Members", outputs_key_field="AccountId" ) def get_members(client: "GuardDutyClient", args: dict): accountId_list = [] accountId_list.append(args.get("accountIds", "")) response = client.get_members(DetectorId=args.get("detectorId", ""), AccountIds=accountId_list) members_response = response.get("Members", []) filtered_members = [member for member in members_response if member] readable_output = tableToMarkdown("AWS GuardDuty Members", filtered_members) if filtered_members else "No result were found" return CommandResults( readable_output=readable_output, outputs=filtered_members, outputs_prefix="AWS.GuardDuty.Members", outputs_key_field="AccountId", ) def connection_test(client: "GuardDutyClient"): response = client.list_detectors() if response.get("DetectorIds"): return "ok" else: raise Exception(f"Error listing detectors. Response was {response}") def main(): # pragma: no cover params = demisto.params() aws_default_region = params.get("defaultRegion") aws_role_arn = params.get("roleArn") aws_role_session_name = params.get("roleSessionName") aws_role_session_duration = params.get("sessionDuration") aws_role_policy = None aws_access_key_id = params.get("credentials", {}).get("identifier") or params.get("access_key") aws_secret_access_key = params.get("credentials", {}).get("password") or params.get("secret_key") aws_gd_severity = params.get("gs_severity", []) verify_certificate = not params.get("insecure", True) timeout = params.get("timeout") or 1 retries = params.get("retries") or 5 first_fetch_time = params.get("first_fetch_time", "10 minutes").strip() fetch_limit = arg_to_number(params.get("fetch_limit", 10)) is_archive = argToBoolean(params.get("is_archive", False)) sts_endpoint_url = params.get("sts_endpoint_url") or None endpoint_url = params.get("endpoint_url") or None try: validate_params(aws_default_region, aws_role_arn, aws_role_session_name, aws_access_key_id, aws_secret_access_key) aws_client = AWSClient( aws_default_region, aws_role_arn, aws_role_session_name, aws_role_session_duration, aws_role_policy, aws_access_key_id, aws_secret_access_key, verify_certificate, timeout, retries, sts_endpoint_url=sts_endpoint_url, endpoint_url=endpoint_url, ) args = demisto.args() client: GuardDutyClient = aws_client.aws_session( service=SERVICE, region=args.get("region"), role_arn=args.get("roleArn"), role_session_name=args.get("roleSessionName"), role_session_duration=args.get("roleSessionDuration"), ) # The command demisto.command() holds the command sent from the user. if demisto.command() == "test-module": # This is the call made when pressing the integration test button. result = connection_test(client) elif demisto.command() == "aws-gd-create-detector": result = create_detector(client, demisto.args()) elif demisto.command() == "aws-gd-delete-detector": result = delete_detector(client, demisto.args()) elif demisto.command() == "aws-gd-get-detector": result = get_detector(client, demisto.args()) elif demisto.command() == "aws-gd-update-detector": result = update_detector(client, demisto.args()) elif demisto.command() == "aws-gd-create-ip-set": result = create_ip_set(client, demisto.args()) elif demisto.command() == "aws-gd-delete-ip-set": result = delete_ip_set(client, demisto.args()) elif demisto.command() == "aws-gd-list-detectors": result = list_detectors(client, demisto.args()) elif demisto.command() == "aws-gd-update-ip-set": result = update_ip_set(client, demisto.args()) elif demisto.command() == "aws-gd-get-ip-set": result = get_ip_set(client, demisto.args()) elif demisto.command() == "aws-gd-list-ip-sets": result = list_ip_sets(client, demisto.args()) elif demisto.command() == "aws-gd-create-threatintel-set": result = create_threat_intel_set(client, demisto.args()) elif demisto.command() == "aws-gd-delete-threatintel-set": result = delete_threat_intel_set(client, demisto.args()) elif demisto.command() == "aws-gd-get-threatintel-set": result = get_threat_intel_set(client, demisto.args()) elif demisto.command() == "aws-gd-list-threatintel-sets": result = list_threat_intel_sets(client, demisto.args()) elif demisto.command() == "aws-gd-update-threatintel-set": result = update_threat_intel_set(client, demisto.args()) elif demisto.command() == "aws-gd-list-findings": result = list_findings(client, demisto.args()) elif demisto.command() == "aws-gd-get-findings": result = get_findings(client, demisto.args()) elif demisto.command() == "aws-gd-create-sample-findings": result = create_sample_findings(client, demisto.args()) elif demisto.command() == "aws-gd-archive-findings": result = archive_findings(client, demisto.args()) elif demisto.command() == "aws-gd-unarchive-findings": result = unarchive_findings(client, demisto.args()) elif demisto.command() == "aws-gd-update-findings-feedback": result = update_findings_feedback(client, demisto.args()) elif demisto.command() == "aws-gd-list-members": result = list_members(client, demisto.args()) elif demisto.command() == "aws-gd-get-members": result = get_members(client, demisto.args()) elif demisto.command() == "fetch-incidents": next_run, incidents = fetch_incidents( client=client, aws_gd_severity=aws_gd_severity, last_run=demisto.getLastRun(), fetch_limit=fetch_limit, # type: ignore[arg-type] first_fetch_time=first_fetch_time, is_archive=is_archive, ) demisto.setLastRun(next_run) demisto.incidents(incidents) sys.exit(0) else: raise NotImplementedError(f"Command {demisto.command()} is not implemented in AWSGuardDuty integration.") return_results(result) except Exception as e: return_error(f"Error has occurred in the AWS GuardDuty Integration: {type(e)}\n {e!s}") if __name__ in ("__main__", "__builtin__", "builtins"): # pragma: no cover main()