Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_guardduty_detector: add support for datasources and s3_logs #19954

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/19954.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_guardduty_detector: Add `datasources` argument
```
117 changes: 109 additions & 8 deletions aws/resource_aws_guardduty_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,56 @@ func resourceAwsGuardDutyDetector() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"enable": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"account_id": {
Type: schema.TypeString,
Computed: true,
},

"arn": {
Type: schema.TypeString,
Computed: true,
},

"datasources": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"s3_logs": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enable": {
Type: schema.TypeBool,
Required: true,
},
},
},
},
},
},
},

"enable": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},

// finding_publishing_frequency is marked as Computed:true since
// GuardDuty member accounts inherit setting from master account
"finding_publishing_frequency": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"tags": tagsSchema(),

"tags": tagsSchema(),
"tags_all": tagsSchemaComputed(),
},

Expand All @@ -67,6 +95,10 @@ func resourceAwsGuardDutyDetectorCreate(d *schema.ResourceData, meta interface{}
input.FindingPublishingFrequency = aws.String(v.(string))
}

if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
input.DataSources = expandGuardDutyDataSourceConfigurations(v.([]interface{})[0].(map[string]interface{}))
}

if len(tags) > 0 {
input.Tags = tags.IgnoreAws().GuarddutyTags()
}
Expand Down Expand Up @@ -111,7 +143,16 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{})
d.Set("arn", arn)

d.Set("account_id", meta.(*AWSClient).accountid)
d.Set("enable", *gdo.Status == guardduty.DetectorStatusEnabled)

if gdo.DataSources != nil {
if err := d.Set("datasources", []interface{}{flattenGuardDutyDataSourceConfigurationsResult(gdo.DataSources)}); err != nil {
return fmt.Errorf("error setting datasources: %w", err)
}
} else {
d.Set("datasources", nil)
}

d.Set("enable", aws.StringValue(gdo.Status) == guardduty.DetectorStatusEnabled)
d.Set("finding_publishing_frequency", gdo.FindingPublishingFrequency)

tags := keyvaluetags.GuarddutyKeyValueTags(gdo.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig)
Expand All @@ -131,13 +172,17 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{})
func resourceAwsGuardDutyDetectorUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).guarddutyconn

if d.HasChanges("enable", "finding_publishing_frequency") {
if d.HasChangesExcept("tags", "tags_all") {
input := guardduty.UpdateDetectorInput{
DetectorId: aws.String(d.Id()),
Enable: aws.Bool(d.Get("enable").(bool)),
FindingPublishingFrequency: aws.String(d.Get("finding_publishing_frequency").(string)),
}

if d.HasChange("datasources") {
input.DataSources = expandGuardDutyDataSourceConfigurations(d.Get("datasources").([]interface{})[0].(map[string]interface{}))
}

log.Printf("[DEBUG] Update GuardDuty Detector: %s", input)
_, err := conn.UpdateDetector(&input)
if err != nil {
Expand Down Expand Up @@ -187,3 +232,59 @@ func resourceAwsGuardDutyDetectorDelete(d *schema.ResourceData, meta interface{}

return nil
}

func expandGuardDutyDataSourceConfigurations(tfMap map[string]interface{}) *guardduty.DataSourceConfigurations {
if tfMap == nil {
return nil
}

apiObject := &guardduty.DataSourceConfigurations{}

if v, ok := tfMap["s3_logs"].([]interface{}); ok && len(v) > 0 {
apiObject.S3Logs = expandGuardDutyS3LogsConfiguration(v[0].(map[string]interface{}))
}

return apiObject
}

func expandGuardDutyS3LogsConfiguration(tfMap map[string]interface{}) *guardduty.S3LogsConfiguration {
if tfMap == nil {
return nil
}

apiObject := &guardduty.S3LogsConfiguration{}

if v, ok := tfMap["enable"].(bool); ok {
apiObject.Enable = aws.Bool(v)
}

return apiObject
}

func flattenGuardDutyDataSourceConfigurationsResult(apiObject *guardduty.DataSourceConfigurationsResult) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.S3Logs; v != nil {
tfMap["s3_logs"] = []interface{}{flattenGuardDutyS3LogsConfigurationResult(v)}
}

return tfMap
}

func flattenGuardDutyS3LogsConfigurationResult(apiObject *guardduty.S3LogsConfigurationResult) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.Status; v != nil {
tfMap["enable"] = aws.StringValue(v) == guardduty.DataSourceStatusEnabled
}

return tfMap
}
48 changes: 48 additions & 0 deletions aws/resource_aws_guardduty_detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,42 @@ func testAccAwsGuardDutyDetector_tags(t *testing.T) {
})
}

func testAccAwsGuardDutyDetector_datasources_s3logs(t *testing.T) {
resourceName := "aws_guardduty_detector.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, guardduty.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsGuardDutyDetectorDestroy,
Steps: []resource.TestStep{
{
Config: testAccGuardDutyDetectorConfigDatasourcesS3Logs(true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsGuardDutyDetectorExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "datasources.#", "1"),
resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.enable", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccGuardDutyDetectorConfigDatasourcesS3Logs(false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsGuardDutyDetectorExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "datasources.#", "1"),
resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.enable", "false"),
),
},
},
})
}

func testAccCheckAwsGuardDutyDetectorDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).guarddutyconn

Expand Down Expand Up @@ -239,3 +275,15 @@ resource "aws_guardduty_detector" "test" {
}
`, tagKey1, tagValue1, tagKey2, tagValue2)
}

func testAccGuardDutyDetectorConfigDatasourcesS3Logs(enable bool) string {
return fmt.Sprintf(`
resource "aws_guardduty_detector" "test" {
datasources {
s3_logs {
enable = %[1]t
}
}
}
`, enable)
}
9 changes: 5 additions & 4 deletions aws/resource_aws_guardduty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
func TestAccAWSGuardDuty_serial(t *testing.T) {
testCases := map[string]map[string]func(t *testing.T){
"Detector": {
"basic": testAccAwsGuardDutyDetector_basic,
"tags": testAccAwsGuardDutyDetector_tags,
"datasource_basic": testAccAWSGuarddutyDetectorDataSource_basic,
"datasource_id": testAccAWSGuarddutyDetectorDataSource_Id,
"basic": testAccAwsGuardDutyDetector_basic,
"datasources_s3logs": testAccAwsGuardDutyDetector_datasources_s3logs,
"tags": testAccAwsGuardDutyDetector_tags,
"datasource_basic": testAccAWSGuarddutyDetectorDataSource_basic,
"datasource_id": testAccAWSGuarddutyDetectorDataSource_Id,
},
"Filter": {
"basic": testAccAwsGuardDutyFilter_basic,
Expand Down
19 changes: 19 additions & 0 deletions website/docs/r/guardduty_detector.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ Provides a resource to manage a GuardDuty detector.
```terraform
resource "aws_guardduty_detector" "MyDetector" {
enable = true

datasources {
s3_logs {
enable = true
}
}
}
```

Expand All @@ -26,8 +32,21 @@ The following arguments are supported:

* `enable` - (Optional) Enable monitoring and feedback reporting. Setting to `false` is equivalent to "suspending" GuardDuty. Defaults to `true`.
* `finding_publishing_frequency` - (Optional) Specifies the frequency of notifications sent for subsequent finding occurrences. If the detector is a GuardDuty member account, the value is determined by the GuardDuty primary account and cannot be modified, otherwise defaults to `SIX_HOURS`. For standalone and GuardDuty primary accounts, it must be configured in Terraform to enable drift detection. Valid values for standalone and primary accounts: `FIFTEEN_MINUTES`, `ONE_HOUR`, `SIX_HOURS`. See [AWS Documentation](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings_cloudwatch.html#guardduty_findings_cloudwatch_notification_frequency) for more information.
* `datasources` - (Optional) Describes which data sources will be enabled for the detector. See [Data Sources](#data-sources) below for more details.
* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.

### Data Sources

The `datasources` block supports the following:

* `s3_logs` - (Optional) Describes whether S3 data event logs are enabled as a data source. See [S3 Logs](#s3-logs) below for more details.

### S3 Logs

This `s3_logs` block supports the following:

* `enable` - (Required) If true, enables [S3 Protection](https://docs.aws.amazon.com/guardduty/latest/ug/s3_detection.html). Defaults to `true`.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down