AWS - GuardDuty

Amazon Web Services Guard Duty Service (gd).

IT Services · AWS - GuardDuty

Details

IDAWS - GuardDuty
ProviderAmazon
CategoryIT Services
From Version5.0.0
Docker Imagedemisto/boto3py3:1.0.0.10221838
Supported ModulesAgentix 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 Arn
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • roleSessionName — Role Session Name
  • sessionDuration — Role Session Duration
  • credentials — Access Key
  • access_key — Access Key
  • secret_key — Secret Key
  • timeout — Timeout
  • retries — Retries
  • endpoint_url — PrivateLink service URL.
  • sts_endpoint_url — STS PrivateLink URL.
  • sts_regional_endpoint — AWS STS Regional Endpoints
  • fetch_limit — How many incidents to fetch each time
  • first_fetch_time — First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year)
  • gs_severity — Guard Duty Severity level
  • is_archive — Archive findings After Fetch
  • incidentFetchInterval — Incidents Fetch Interval
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (23)

  • aws-gd-archive-findings

    Archives Amazon GuardDuty findings specified by the list of finding IDs.

  • aws-gd-create-detector

    Create an AWS Guard Duty Detector on the integration instance specified aws account.

  • aws-gd-create-ip-set

    A list of trusted IP addresses on allow list for secure communication with AWS infrastructure and applications.

  • 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-gd-create-threatintel-set

    Create a new ThreatIntelSet. ThreatIntelSets consist of known malicious IP addresses. GuardDuty generates findings based on ThreatIntelSets.

  • aws-gd-delete-detector

    Deletes a Amazon GuardDuty detector specified by the detector ID.

  • aws-gd-delete-ip-set

    Deletes the IPSet specified by the IPSet ID.

  • aws-gd-delete-threatintel-set

    Deletes ThreatIntelSet specified by the ThreatIntelSet ID.

  • aws-gd-get-detector

    Retrieves an Amazon GuardDuty detector specified by the detectorId.

  • aws-gd-get-findings

    Describes Amazon GuardDuty findings specified by finding IDs.

  • aws-gd-get-ip-set

    Retrieves the IPSet specified by the IPSet ID.

  • aws-gd-get-members

    Describes Amazon GuardDuty members for the specified detector ID & account ID.

  • aws-gd-get-threatintel-set

    Retrieves the ThreatIntelSet that is specified by the ThreatIntelSet ID.

  • aws-gd-list-detectors

    Lists detectorIds of all the existing Amazon GuardDuty detector resources.

  • aws-gd-list-findings

    Lists Amazon GuardDuty findings for the specified detector ID.

  • aws-gd-list-ip-sets

    Lists the IPSets of the GuardDuty service specified by the detector ID.

  • aws-gd-list-members

    Describes Amazon GuardDuty members for the specified detector ID.

  • aws-gd-list-threatintel-sets

    Lists the ThreatIntelSets of the GuardDuty service specified by the detector ID.

  • aws-gd-unarchive-findings

    Unarchives Amazon GuardDuty findings specified by the list of finding IDs.

  • aws-gd-update-detector

    Updates an Amazon GuardDuty detector specified by the detectorId.

  • aws-gd-update-findings-feedback

    Marks specified Amazon GuardDuty findings as useful or not useful.

  • aws-gd-update-ip-set

    Updates the IPSet specified by the IPSet ID.

  • aws-gd-update-threatintel-set

    Updates the ThreatIntelSet specified by ThreatIntelSet ID.

import json
from contextlib import nullcontext as does_not_raise

import demistomock as demisto  # noqa: F401
import pytest
from AWSGuardDuty import (
    archive_findings,
    connection_test,
    create_detector,
    create_ip_set,
    create_sample_findings,
    create_threat_intel_set,
    delete_detector,
    delete_ip_set,
    delete_threat_intel_set,
    fetch_incidents,
    get_detector,
    get_findings,
    get_ip_set,
    get_members,
    get_threat_intel_set,
    list_detectors,
    list_findings,
    list_ip_sets,
    list_members,
    list_threat_intel_sets,
    parse_incident_from_finding,
    unarchive_findings,
    update_detector,
    update_findings_feedback,
    update_ip_set,
    update_threat_intel_set,
)
from test_data.api_responses_for_test import (
    DETECTOR_RESPONSE,
    FINDING,
    GET_MEMBERS_RESPONSE,
    IP_SET_RESPONSE,
    LIST_MEMBERS_RESPONSE,
    RESPONSE_METADATA,
    THREAT_INTEL_SET_RESPONSE,
)


class MockedBoto3Client:
    """Mocked AWSClient session for easier expectation settings."""

    def list_detectors(self, **kwargs):
        pass

    def list_findings(self, **kwargs):
        pass

    def get_findings(self, **kwargs):
        pass

    def archive_findings(self, **kwargs):
        pass

    def create_sample_findings(self, **kwargs):
        pass

    def unarchive_findings(self, **kwargs):
        pass

    def update_findings_feedback(self, **kwargs):
        pass

    def list_members(self, **kwargs):
        pass

    def get_members(self, **kwargs):
        pass

    def create_detector(self, **kwargs):
        pass

    def update_detector(self, **kwargs):
        pass

    def delete_detector(self, **kwargs):
        pass

    def get_detector(self, **kwargs):
        pass

    def create_ip_set(self, **kwargs):
        pass

    def delete_ip_set(self, **kwargs):
        pass

    def update_ip_set(self, **kwargs):
        pass

    def get_ip_set(self, **kwargs):
        pass

    def list_ip_sets(self, **kwargs):
        pass

    def create_threat_intel_set(self, **kwargs):
        pass

    def delete_threat_intel_set(self, **kwargs):
        pass

    def get_threat_intel_set(self, **kwargs):
        pass

    def list_threat_intel_sets(self, **kwargs):
        pass

    def update_threat_intel_set(self, **kwargs):
        pass

    def get_paginator(self, **kwargs):
        pass


def test_get_members(mocker):
    """
    Given
    - get-members command

    When
    - running get-members, that returns empty map

    Then
    - Ensure that empty map is not returned to the context
    """
    client = MockedBoto3Client()
    get_members_mock = mocker.patch.object(MockedBoto3Client, "get_members", side_effect=[GET_MEMBERS_RESPONSE])
    command_results = get_members(client, {})
    assert command_results.outputs == [{"AccountId": 1, "DetectorId": 1, "MasterId": 1}]
    assert get_members_mock.is_called_once()


def test_parse_incident_from_finding():
    """
    Given:
    - Amazon GuardDuty finding with datetime object nested in it

    When:
    - Parsing finding to incident

    Then:
    - Ensure finding is parsed as expected
    """
    title = "title"
    desc = "desc"
    incident = parse_incident_from_finding(FINDING)
    assert incident["name"] == title
    assert incident["details"] == desc
    assert incident["severity"] == 0
    assert "2015-01-01" in incident["rawJSON"]


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({"DetectorIds": ["detector_id1"]}, does_not_raise(), id="Success"),
        pytest.param({}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_test_module(mocker, response, raises):
    """
    Given:
        AWSClient session
        list_detectors valid responses

    When:
        Running test-module command

    Then:
        assert no exception is being raised.
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    list_detectors_mock = mocker.patch.object(MockedBoto3Client, "list_detectors", side_effect=[response])

    with raises:
        connection_test(mocked_client)

    assert list_detectors_mock.is_called_once()


def test_list_members(mocker):
    """
    Given:
        AWSClient session
        list_members valid response

    When:
        Running list_members command

    Then:
        assert no exception is being raised.
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    get_paginator_mock = mocker.patch.object(MockedBoto3Client, "get_paginator", side_effect=[MockedPaginator()])
    paginate_mock = mocker.patch.object(MockedPaginator, "paginate", side_effect=[[LIST_MEMBERS_RESPONSE]])

    command_results = list_members(mocked_client, {"detectorId": "some_id"})

    get_paginator_mock.assert_called_with("list_members")
    paginate_mock.assert_called_with(DetectorId="some_id", PaginationConfig={"MaxItems": 50, "PageSize": 50})
    assert command_results.outputs == [{"Member": LIST_MEMBERS_RESPONSE.get("Members")[0]}]


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_update_findings_feedback(mocker, response, raises):
    """
    Given:
        AWSClient session
        update_findings_feedback various response

    When:
        Running update_findings_feedback command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    update_findings_feedback_mock = mocker.patch.object(MockedBoto3Client, "update_findings_feedback", side_effect=[response])

    with raises:
        update_findings_feedback(
            mocked_client,
            {
                "detectorId": "some_id",
                "findingIds": "finding_id1, finding_id2",
                "comments": "some_comment1, some_comment2",
                "feedback": "USEFUL",
            },
        )

    update_findings_feedback_mock.assert_called_with(
        DetectorId="some_id",
        FindingIds=["finding_id1", "finding_id2"],
        Comments="some_comment1, some_comment2",
        Feedback="USEFUL",
    )


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_archive_findings(mocker, response, raises):
    """
    Given:
        AWSClient session
        archive_findings various response

    When:
        Running archive_findings command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    archive_findings_mock = mocker.patch.object(MockedBoto3Client, "archive_findings", side_effect=[response])

    with raises:
        archive_findings(mocked_client, {"detectorId": "some_id", "findingIds": "finding_id1, finding_id2"})

    archive_findings_mock.assert_called_with(DetectorId="some_id", FindingIds=["finding_id1", "finding_id2"])


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_unarchive_findings(mocker, response, raises):
    """
    Given:
        AWSClient session
        unarchive_findings various response

    When:
        Running unarchive_findings command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    unarchive_findings_mock = mocker.patch.object(MockedBoto3Client, "unarchive_findings", side_effect=[response])

    with raises:
        unarchive_findings(mocked_client, {"detectorId": "some_id", "findingIds": "finding_id1, finding_id2"})

    unarchive_findings_mock.assert_called_with(DetectorId="some_id", FindingIds=["finding_id1", "finding_id2"])


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_create_sample_findings(mocker, response, raises):
    """
    Given:
        AWSClient session
        create_sample_findings various response

    When:
        Running create_sample_findings command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once.
    """
    mocked_client = MockedBoto3Client()
    create_sample_findings_mock = mocker.patch.object(MockedBoto3Client, "create_sample_findings", side_effect=[response])

    with raises:
        create_sample_findings(mocked_client, {"detectorId": "some_id", "findingTypes": "finding_type1, finding_type2"})

    create_sample_findings_mock.assert_called_with(DetectorId="some_id", FindingTypes=["finding_type1", "finding_type2"])


EXPECTED_FINDING_RESULT = {
    "AccountId": "string",
    "Arn": "string",
    "CreatedAt": "string",
    "Description": "desc",
    "Id": "string",
    "Region": "string",
    "Title": "title",
    "Type": "string",
}


def test_get_findings(mocker):
    """
    Given:
        AWSClient session
        get_findings valid response

    When:
        Running get_findings command

    Then:
        assert api calls are called exactly once and as expected.
    """
    from test_data.get_findings_expected_outputs import EXPECTED_FINDING_OUTPUTS

    mocked_client = MockedBoto3Client()
    get_findings_mock = mocker.patch.object(
        MockedBoto3Client,
        "get_findings",
        side_effect=[{"Findings": [FINDING, update_finding_id(FINDING.copy(), "finding2", "2022-09-07T13:48:00.814Z")]}],
    )

    command_results = get_findings(mocked_client, {"detectorId": "some_id", "findingIds": "finding_id1, finding_id2"})

    get_findings_mock.assert_called_with(DetectorId="some_id", FindingIds=["finding_id1", "finding_id2"])
    assert command_results.get("EntryContext") == EXPECTED_FINDING_OUTPUTS


class MockedPaginator:
    def paginate(self, **kwargs):
        pass


def test_list_findings(mocker):
    """
    Given:
        AWSClient session
        list_findings valid response

    When:
        Running list_findings command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_paginator_mock = mocker.patch.object(MockedBoto3Client, "get_paginator", side_effect=[MockedPaginator()])
    paginate_mock = mocker.patch.object(
        MockedPaginator,
        "paginate",
        side_effect=[[{"FindingIds": ["finding1", "finding2"]}, {"FindingIds": ["finding3", "finding4"]}]],
    )

    command_results = list_findings(mocked_client, {"detectorId": "some_id"})

    get_paginator_mock.assert_called_with("list_findings")
    paginate_mock.assert_called_with(DetectorId="some_id", PaginationConfig={"MaxItems": 50, "PageSize": 50})

    assert command_results.outputs == [
        {"FindingId": "finding1"},
        {"FindingId": "finding2"},
        {"FindingId": "finding3"},
        {"FindingId": "finding4"},
    ]


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_update_threat_intel_set(mocker, response, raises):
    """
    Given:
        AWSClient session
        update_threat_intel_set various responses

    When:
        Running update_threat_intel_set command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    update_threat_intel_set_mock = mocker.patch.object(MockedBoto3Client, "update_threat_intel_set", side_effect=[response])

    with raises:
        update_threat_intel_set(
            mocked_client,
            {
                "detectorId": "some_id",
                "threatIntelSetId": "ThreatIntelSetId1",
                "activate": "True",
                "location": "here",
                "name": "some_name",
            },
        )

    update_threat_intel_set_mock.assert_called_with(
        DetectorId="some_id", ThreatIntelSetId="ThreatIntelSetId1", Activate=True, Location="here", Name="some_name"
    )


EXPECTED_THREAT_INTEL_RESULT = {
    "DetectorId": "some_id",
    "Format": "TXT",
    "Location": "string",
    "Name": "string",
    "Status": "INACTIVE",
    "ThreatIntelSetId": "threat_id1",
}


def test_get_threat_intel_set(mocker):
    """
    Given:
        AWSClient session
        get_threat_intel_set valid response

    When:
        Running get_threat_intel_set command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_threat_intel_set_mock = mocker.patch.object(
        MockedBoto3Client, "get_threat_intel_set", side_effect=[THREAT_INTEL_SET_RESPONSE]
    )

    command_results = get_threat_intel_set(mocked_client, {"detectorId": "some_id", "threatIntelSetId": "threat_id1"})

    get_threat_intel_set_mock.assert_called_with(DetectorId="some_id", ThreatIntelSetId="threat_id1")
    assert command_results.outputs == EXPECTED_THREAT_INTEL_RESULT


def test_list_threat_intel_sets(mocker):
    """
    Given:
        AWSClient session
        list_threat_intel_set valid response

    When:
        Running list_threat_intel_set command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_paginator_mock = mocker.patch.object(MockedBoto3Client, "get_paginator", side_effect=[MockedPaginator()])
    paginate_mock = mocker.patch.object(
        MockedPaginator, "paginate", side_effect=[[{"ThreatIntelSetIds": ["threat1", "threat2"]}]]
    )

    command_results = list_threat_intel_sets(mocked_client, {"detectorId": "some_id"})

    get_paginator_mock.assert_called_with("list_threat_intel_sets")
    paginate_mock.assert_called_with(DetectorId="some_id", PaginationConfig={"MaxItems": 50, "PageSize": 50})
    assert command_results.outputs == [
        {"DetectorId": "some_id"},
        {"ThreatIntelSetId": "threat1"},
        {"ThreatIntelSetId": "threat2"},
    ]


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_delete_threat_intel_set(mocker, response, raises):
    """
    Given:
        AWSClient session
        list_threat_intel_set various response

    When:
        Running list_threat_intel_set command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    delete_threat_intel_set_mock = mocker.patch.object(MockedBoto3Client, "delete_threat_intel_set", side_effect=[response])

    with raises:
        delete_threat_intel_set(mocked_client, {"detectorId": "some_id", "threatIntelSetId": "ThreatIntelSetId1"})

    delete_threat_intel_set_mock.assert_called_with(DetectorId="some_id", ThreatIntelSetId="ThreatIntelSetId1")


def test_create_threat_intel_set(mocker):
    """
    Given:
        AWSClient session
        create_threat_intel_set valid response

    When:
        Running create_threat_intel_set command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    create_threat_intel_set_mock = mocker.patch.object(
        MockedBoto3Client, "create_threat_intel_set", side_effect=[{"ThreatIntelSetId": "threat1"}]
    )

    command_results = create_threat_intel_set(
        mocked_client,
        {"detectorId": "some_id", "activate": "True", "format": "some_format", "location": "some_location", "name": "some_name"},
    )

    create_threat_intel_set_mock.assert_called_with(
        DetectorId="some_id", Activate=True, Format="some_format", Location="some_location", Name="some_name"
    )
    assert command_results.outputs == {"DetectorId": "some_id", "ThreatIntelSetId": "threat1"}


EXPECTED_IP_SET_RESULT = {
    "DetectorId": "some_id",
    "Format": "TXT",
    "IpSetId": "ipset1",
    "Location": "string",
    "Name": "string",
    "Status": "INACTIVE",
}


def test_get_ip_set(mocker):
    """
    Given:
        AWSClient session
        get_ip_set valid response

    When:
        Running get_ip_set command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_ip_set_mock = mocker.patch.object(MockedBoto3Client, "get_ip_set", side_effect=[IP_SET_RESPONSE])

    command_results = get_ip_set(mocked_client, {"detectorId": "some_id", "ipSetId": "ipset1"})

    get_ip_set_mock.assert_called_with(DetectorId="some_id", IpSetId="ipset1")
    assert command_results.outputs == EXPECTED_IP_SET_RESULT


def test_list_ip_sets(mocker):
    """
    Given:
        AWSClient session
        list_ip_sets valid response

    When:
        Running list_ip_sets command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_paginator_mock = mocker.patch.object(MockedBoto3Client, "get_paginator", side_effect=[MockedPaginator()])
    paginate_mock = mocker.patch.object(MockedPaginator, "paginate", side_effect=[[{"IpSetIds": ["ipset1", "ipset2"]}]])

    command_results = list_ip_sets(mocked_client, {"detectorId": "some_id"})

    get_paginator_mock.assert_called_with("list_ip_sets")
    paginate_mock.assert_called_with(DetectorId="some_id", PaginationConfig={"MaxItems": 50, "PageSize": 50})

    assert command_results.outputs == [{"DetectorId": "some_id"}, {"IpSetId": "ipset1"}, {"IpSetId": "ipset2"}]


def test_create_ip_set(mocker):
    """
    Given:
        AWSClient session
        create_ip_set valid response

    When:
        Running create_ip_set command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    create_ip_set_mock = mocker.patch.object(MockedBoto3Client, "create_ip_set", side_effect=[{"IpSetId": "ipset1"}])

    command_results = create_ip_set(
        mocked_client,
        {"detectorId": "some_id", "activate": "True", "format": "some_format", "location": "some_location", "name": "some_name"},
    )

    create_ip_set_mock.assert_called_with(
        DetectorId="some_id", Activate=True, Format="some_format", Location="some_location", Name="some_name"
    )
    assert command_results.outputs == {"DetectorId": "some_id", "IpSetId": "ipset1"}


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_update_ip_set(mocker, response, raises):
    """
    Given:
        AWSClient session
        update_ip_set various response

    When:
        Running update_ip_set command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    update_ip_set_mock = mocker.patch.object(MockedBoto3Client, "update_ip_set", side_effect=[response])

    with raises:
        update_ip_set(
            mocked_client,
            {"detectorId": "some_id", "ipSetId": "ipSetId1", "activate": "True", "location": "here", "name": "some_name"},
        )

    update_ip_set_mock.assert_called_with(
        DetectorId="some_id", IpSetId="ipSetId1", Activate=True, Location="here", Name="some_name"
    )


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_delete_ip_set(mocker, response, raises):
    """
    Given:
        AWSClient session
        delete_ip_set various response

    When:
        Running delete_ip_set command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    delete_ip_set_mock = mocker.patch.object(MockedBoto3Client, "delete_ip_set", side_effect=[response])

    with raises:
        delete_ip_set(mocked_client, {"detectorId": "some_id", "ipSetId": "IpSetId1"})

    delete_ip_set_mock.assert_called_with(DetectorId="some_id", IpSetId="IpSetId1")


@pytest.mark.parametrize(
    "args, response_iterator, expected_pagination_config, expected_results",
    [
        ({"limit": "1"}, [{"DetectorIds": ["detector1"]}], {"MaxItems": 1, "PageSize": 50}, [{"DetectorId": "detector1"}]),
        (
            {"page_size": "2", "page": "2"},
            [{"DetectorIds": ["detector1", "detector2"]}, {"DetectorIds": ["detector3", "detector4"]}],
            {"MaxItems": 4, "PageSize": 2},
            [{"DetectorId": "detector3"}, {"DetectorId": "detector4"}],
        ),
    ],
)
def test_list_detectors(mocker, args, response_iterator, expected_pagination_config, expected_results):
    """
    Given:
        AWSClient session
        list_detectors valid response

    When:
        Running list_detectors command with: 1. limit = 1 (Automatic Pagination)
                                             2. page_size = 2, page = 2 (Manual Pagination)
    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_paginator_mock = mocker.patch.object(MockedBoto3Client, "get_paginator", side_effect=[MockedPaginator()])
    paginate_mock = mocker.patch.object(MockedPaginator, "paginate", side_effect=[response_iterator])

    command_results = list_detectors(mocked_client, args)

    get_paginator_mock.assert_called_with("list_detectors")
    paginate_mock.assert_called_with(PaginationConfig=expected_pagination_config)
    assert command_results.outputs == expected_results


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_update_detector(mocker, response, raises):
    """
    Given:
        AWSClient session
        update_detector various response

    When:
        Running update_detector command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    update_detector_mock = mocker.patch.object(MockedBoto3Client, "update_detector", side_effect=[response])

    with raises:
        update_detector(
            mocked_client,
            {
                "enable": "True",
                "detectorId": "some_id",
                "findingFrequency": "One Hour",
                "enableKubernetesLogs": "True",
                "ebsVolumesMalwareProtection": "True",
                "enableS3Logs": "True",
            },
        )
    assert update_detector_mock.call_args_list[0][1] == {
        "Enable": True,
        "DetectorId": "some_id",
        "FindingPublishingFrequency": "ONE_HOUR",
        "DataSources": {
            "S3Logs": {"Enable": True},
            "Kubernetes": {"AuditLogs": {"Enable": True}},
            "MalwareProtection": {"ScanEc2InstanceWithFindings": {"EbsVolumes": True}},
        },
    }


@pytest.mark.parametrize(
    "response, raises",
    [
        pytest.param({}, does_not_raise(), id="Success"),
        pytest.param(RESPONSE_METADATA, does_not_raise(), id="Success with Metadata"),
        pytest.param({"response": "bad"}, pytest.raises(Exception), id="Failure"),
    ],
)
def test_delete_detector(mocker, response, raises):
    """
    Given:
        AWSClient session
        delete_detector various response

    When:
        Running delete_detector command

    Then:
        assert exceptions are being raised according to api response
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    delete_detector_mock = mocker.patch.object(MockedBoto3Client, "delete_detector", side_effect=[response])

    with raises:
        delete_detector(mocked_client, {"detectorId": "some_id", "ipSetId": "IpSetId1"})

    delete_detector_mock.assert_called_with(DetectorId="some_id")


EXPECTED_DETECTOR_RESPONSE = {
    "CloudTrailStatus": "ENABLED",
    "CreatedAt": "string",
    "DNSLogsStatus": "ENABLED",
    "DetectorId": "some_id",
    "FlowLogsStatus": "ENABLED",
    "KubernetesAuditLogsStatus": "ENABLED",
    "MalwareProtectionReason": None,
    "MalwareProtectionStatus": "ENABLED",
    "S3LogsStatus": "ENABLED",
    "ServiceRole": "string",
    "Status": "ENABLED",
    "Tags": {"string": "string"},
    "UpdatedAt": "string",
}


def test_get_detector(mocker):
    """
    Given:
        AWSClient session
        get_detector valid response

    When:
        Running get_detector command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    get_detector_mock = mocker.patch.object(MockedBoto3Client, "get_detector", side_effect=[DETECTOR_RESPONSE])

    command_results = get_detector(mocked_client, {"detectorId": "some_id"})

    get_detector_mock.assert_called_with(DetectorId="some_id")
    assert command_results.outputs == EXPECTED_DETECTOR_RESPONSE


def test_create_detector(mocker):
    """
    Given:
        AWSClient session
        create_detector valid response

    When:
        Running create_detector command

    Then:
        assert api calls are called exactly once and as expected.
    """
    mocked_client = MockedBoto3Client()
    create_detector_mock = mocker.patch.object(MockedBoto3Client, "create_detector", side_effect=[{"DetectorId": "some_id"}])

    command_results = create_detector(
        mocked_client,
        {
            "enabled": "True",
            "findingFrequency": "One Hour",
            "enableKubernetesLogs": "True",
            "ebsVolumesMalwareProtection": "True",
            "enableS3Logs": "True",
        },
    )
    assert create_detector_mock.call_args_list[0][1] == {
        "Enable": True,
        "FindingPublishingFrequency": "ONE_HOUR",
        "DataSources": {
            "S3Logs": {"Enable": True},
            "Kubernetes": {"AuditLogs": {"Enable": True}},
            "MalwareProtection": {"ScanEc2InstanceWithFindings": {"EbsVolumes": True}},
        },
    }
    assert command_results.outputs == {"DetectorId": "some_id"}


def update_finding_id(finding, new_id, updated_at=None):
    """Update finding with new id and updatedAt fields."""
    finding["Id"] = new_id
    if updated_at:
        finding["UpdatedAt"] = updated_at
    return finding


""" FETCH CONSTANTS """
FINDING_1 = update_finding_id(FINDING.copy(), "finding_id1")
FINDING_2 = update_finding_id(FINDING.copy(), "finding_id2")
INCIDENT_1 = {
    "name": "title",
    "details": "desc",
    "occurred": "2022-11-08T14:24:52.908Z",
    "severity": 0,
    "rawJSON": json.dumps(FINDING_1, default=str),
}
INCIDENT_2 = {
    "name": "title",
    "details": "desc",
    "occurred": "2022-11-08T14:24:52.908Z",
    "severity": 0,
    "rawJSON": json.dumps(FINDING_2, default=str),
}
INCIDENTS_NEXT_RUN = {
    "latest_created_time": "2022-11-08T14:24:52.908000Z",
    "latest_updated_time": "2022-11-08T14:24:52.908000Z",
    "last_incidents_ids": ["finding_id1", "finding_id2"],
    "last_next_token": "",
}


@pytest.mark.parametrize(
    "gd_severity, "
    "last_run, fetch_limit, first_fetch_time,"
    "expected_incidents, expected_next_run, "
    "expected_criterion_conditions,"
    "mock_list_finding_res, mock_get_finding_res, is_archive",
    [
        # case - 1: First run (no Last Run) should get all incident from 'First fetch timestamp'
        # field to current time.
        # is_archive = True, should archive the findings and to get only unarchived findings.
        (
            ["Medium"],
            {},
            2,
            "2022-11-08T14:24:52.908Z",
            [INCIDENT_1, INCIDENT_2],
            INCIDENTS_NEXT_RUN,
            {"severity": {"Gte": 4}, "service.archived": {"Eq": ["false"]}},
            {"FindingIds": ["finding_id1", "finding_id2"], "NextToken": ""},
            [FINDING_1, FINDING_2],
            True,
        ),
        # case - 2: Second run should get all incidents from last run time to current time
        # without duplicates
        (
            [],
            {
                "last_incidents_ids": ["finding_id1"],
                "last_next_token": "",
                "latest_created_time": "2022-11-08T14:24:52.908000Z",
                "latest_updated_time": "2022-11-08T14:24:52.908000Z",
            },
            2,
            "3 days",
            [INCIDENT_2],
            INCIDENTS_NEXT_RUN,
            {"id": {"Neq": ["finding_id1"]}, "severity": {"Gte": 1}, "updatedAt": {"Gte": 1667917492908}},
            {"FindingIds": ["finding_id2"], "NextToken": ""},
            [FINDING_2],
            False,
        ),
        # case - 3: A run without new finding since last run, should not change the Last Run
        (
            [],
            INCIDENTS_NEXT_RUN,
            2,
            "3 years",
            [],
            INCIDENTS_NEXT_RUN,
            {"severity": {"Gte": 1}, "updatedAt": {"Gte": 1667917492908}, "id": {"Neq": ["finding_id1", "finding_id2"]}},
            {"FindingIds": [], "NextToken": ""},
            [],
            False,
        ),
        # case - 4: A run without incidents (all incidents has earlier time then the last run)
        # should get 0 incidents and should not change the Last Run
        # [incidents created time is 08.11 but latest created time is 16.11]
        (
            [],
            {"latest_created_time": "2022-11-16T14:24:52.908000Z", "latest_updated_time": "2022-11-06T14:24:52.908000Z"},
            2,
            "3 days",
            [],
            {
                "last_incidents_ids": [],
                "last_next_token": "",
                "latest_created_time": "2022-11-16T14:24:52.908000Z",
                "latest_updated_time": "2022-11-08T14:24:52.908000Z",
            },
            {"severity": {"Gte": 1}, "updatedAt": {"Gte": 1667744692908}},
            {"FindingIds": ["finding_id1", "finding_id2"], "NextToken": ""},
            [FINDING_1, FINDING_2],
            False,
        ),
        # case - 5: A run given last_next_token and latest_updated_time,
        # validate the latest_updated_time is not used
        (
            [],
            {
                "last_incidents_ids": [],
                "last_next_token": "test",
                "latest_created_time": "2022-11-08T14:24:52.908000Z",
                "latest_updated_time": "2022-11-11T14:24:52.908000Z",
            },
            2,
            "3 days",
            [INCIDENT_1, INCIDENT_2],
            {
                "last_incidents_ids": ["finding_id1", "finding_id2"],
                "last_next_token": "",
                "latest_created_time": "2022-11-08T14:24:52.908000Z",
                "latest_updated_time": "2022-11-11T14:24:52.908000Z",
            },
            {"severity": {"Gte": 1}},
            {"FindingIds": ["finding_id1", "finding_id2"], "NextToken": ""},
            [FINDING_1, FINDING_2],
            False,
        ),
        # case - 6: A run given last_next_token and latest_updated_time is None,
        # validate the latest_updated_time is not used,
        # and the next run's latest_updated_time is the same as latest_created_time
        (
            [],
            {
                "last_incidents_ids": [],
                "last_next_token": "test",
                "latest_created_time": "2022-11-08T14:24:52.908000Z",
                "latest_updated_time": None,
            },
            2,
            "3 days",
            [INCIDENT_1, INCIDENT_2],
            {
                "last_incidents_ids": ["finding_id1", "finding_id2"],
                "last_next_token": "",
                "latest_created_time": "2022-11-08T14:24:52.908000Z",
                "latest_updated_time": "2022-11-08T14:24:52.908000Z",
            },
            {"severity": {"Gte": 1}},
            {"FindingIds": ["finding_id1", "finding_id2"], "NextToken": ""},
            [FINDING_1, FINDING_2],
            False,
        ),
    ],
    ids=["case - 1", "case - 2", "case - 3", "case - 4", "case - 5", "last_updated_time is None"],
)
def test_fetch_incidents(
    mocker,
    gd_severity,
    last_run,
    fetch_limit,
    first_fetch_time,
    expected_incidents,
    expected_next_run,
    expected_criterion_conditions,
    mock_list_finding_res,
    mock_get_finding_res,
    is_archive,
):
    """
    Given:
        AWSClient session
        list_detectors, list_finding_ids, get_finding_ids valid responses.

    When:
        Running fetch-incidents.

    Then:
        assert incidents are returned as expected.
        assert api calls are called as expected.
    """
    mocked_client = MockedBoto3Client()
    list_detectors_mock = mocker.patch.object(
        MockedBoto3Client, "list_detectors", side_effect=[{"DetectorIds": ["detector_id1"]}]
    )
    list_findings_mock = mocker.patch.object(MockedBoto3Client, "list_findings", return_value=mock_list_finding_res)
    get_findings_mock = mocker.patch.object(MockedBoto3Client, "get_findings", return_value={"Findings": mock_get_finding_res})
    archive_findings_mock = mocker.patch.object(MockedBoto3Client, "archive_findings", side_effect=[{}])

    next_run, incidents = fetch_incidents(
        client=mocked_client,
        aws_gd_severity=gd_severity,
        last_run=last_run,
        fetch_limit=fetch_limit,
        first_fetch_time=first_fetch_time,
        is_archive=is_archive,
    )

    assert list_detectors_mock.is_called_once
    assert list_findings_mock.call_count == 1
    assert get_findings_mock.call_count == 1
    assert list_findings_mock.call_args[1]["FindingCriteria"]["Criterion"] == expected_criterion_conditions
    if is_archive:
        assert archive_findings_mock.call_count == 1
        assert archive_findings_mock.call_args[1]["FindingIds"] == mock_list_finding_res["FindingIds"]
    assert next_run == expected_next_run
    assert incidents == expected_incidents


@pytest.mark.parametrize(
    "args, expected_results",
    [
        ({}, (50, 50, None)),  # no pagination arguments
        ({"limit": "3"}, (3, 50, None)),  # given limit argument
        ({"page_size": "5", "page": "2"}, (10, 5, 2)),
    ],
)  # given page_size and page arguments
def test_get_pagination_args(args, expected_results):
    """
    Given:
        - pagination arguments.

    When:
        - Running a list command.

    Then:
        - Make sure that the correct amount of results to display is returned.
         expected_results = (limit, page_size, page) == get_pagination_args(args)
    """
    from AWSGuardDuty import get_pagination_args

    assert expected_results == get_pagination_args(args)