diff --git a/.changelog/15241.txt b/.changelog/15241.txt new file mode 100644 index 00000000000..906ce6da03f --- /dev/null +++ b/.changelog/15241.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_guardduty_organization_configuration: Add `datasources` argument +``` \ No newline at end of file diff --git a/aws/resource_aws_guardduty_organization_configuration.go b/aws/resource_aws_guardduty_organization_configuration.go index 2a1857bb230..d9d8120eb11 100644 --- a/aws/resource_aws_guardduty_organization_configuration.go +++ b/aws/resource_aws_guardduty_organization_configuration.go @@ -26,6 +26,32 @@ func resourceAwsGuardDutyOrganizationConfiguration() *schema.Resource { Type: schema.TypeBool, Required: true, }, + + "datasources": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + 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{ + "auto_enable": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "detector_id": { Type: schema.TypeString, Required: true, @@ -46,6 +72,10 @@ func resourceAwsGuardDutyOrganizationConfigurationUpdate(d *schema.ResourceData, DetectorId: aws.String(detectorID), } + if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DataSources = expandGuardDutyOrganizationDataSourceConfigurations(v.([]interface{})[0].(map[string]interface{})) + } + _, err := conn.UpdateOrganizationConfiguration(input) if err != nil { @@ -80,8 +110,73 @@ func resourceAwsGuardDutyOrganizationConfigurationRead(d *schema.ResourceData, m return fmt.Errorf("error reading GuardDuty Organization Configuration (%s): empty response", d.Id()) } - d.Set("detector_id", d.Id()) d.Set("auto_enable", output.AutoEnable) + if output.DataSources != nil { + if err := d.Set("datasources", []interface{}{flattenGuardDutyOrganizationDataSourceConfigurationsResult(output.DataSources)}); err != nil { + return fmt.Errorf("error setting datasources: %w", err) + } + } else { + d.Set("datasources", nil) + } + + d.Set("detector_id", d.Id()) + return nil } + +func expandGuardDutyOrganizationDataSourceConfigurations(tfMap map[string]interface{}) *guardduty.OrganizationDataSourceConfigurations { + if tfMap == nil { + return nil + } + + apiObject := &guardduty.OrganizationDataSourceConfigurations{} + + if v, ok := tfMap["s3_logs"].([]interface{}); ok && len(v) > 0 { + apiObject.S3Logs = expandGuardDutyOrganizationS3LogsConfiguration(v[0].(map[string]interface{})) + } + + return apiObject +} + +func expandGuardDutyOrganizationS3LogsConfiguration(tfMap map[string]interface{}) *guardduty.OrganizationS3LogsConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &guardduty.OrganizationS3LogsConfiguration{} + + if v, ok := tfMap["auto_enable"].(bool); ok { + apiObject.AutoEnable = aws.Bool(v) + } + + return apiObject +} + +func flattenGuardDutyOrganizationDataSourceConfigurationsResult(apiObject *guardduty.OrganizationDataSourceConfigurationsResult) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.S3Logs; v != nil { + tfMap["s3_logs"] = []interface{}{flattenGuardDutyOrganizationS3LogsConfigurationResult(v)} + } + + return tfMap +} + +func flattenGuardDutyOrganizationS3LogsConfigurationResult(apiObject *guardduty.OrganizationS3LogsConfigurationResult) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.AutoEnable; v != nil { + tfMap["auto_enable"] = aws.BoolValue(v) + } + + return tfMap +} diff --git a/aws/resource_aws_guardduty_organization_configuration_test.go b/aws/resource_aws_guardduty_organization_configuration_test.go index 5d31055cf7b..8bd7ec2bd31 100644 --- a/aws/resource_aws_guardduty_organization_configuration_test.go +++ b/aws/resource_aws_guardduty_organization_configuration_test.go @@ -46,6 +46,44 @@ func testAccAwsGuardDutyOrganizationConfiguration_basic(t *testing.T) { }) } +func testAccAwsGuardDutyOrganizationConfiguration_s3logs(t *testing.T) { + detectorResourceName := "aws_guardduty_detector.test" + resourceName := "aws_guardduty_organization_configuration.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOrganizationsAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, guardduty.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsGuardDutyDetectorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGuardDutyOrganizationConfigurationConfigS3Logs(true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_enable", "true"), + resource.TestCheckResourceAttrPair(resourceName, "detector_id", detectorResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.auto_enable", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGuardDutyOrganizationConfigurationConfigS3Logs(false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_enable", "true"), + resource.TestCheckResourceAttrPair(resourceName, "detector_id", detectorResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.auto_enable", "false"), + ), + }, + }, + }) +} + func testAccGuardDutyOrganizationConfigurationConfigAutoEnable(autoEnable bool) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} @@ -73,3 +111,37 @@ resource "aws_guardduty_organization_configuration" "test" { } `, autoEnable) } + +func testAccGuardDutyOrganizationConfigurationConfigS3Logs(autoEnable bool) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +data "aws_partition" "current" {} + +resource "aws_organizations_organization" "test" { + aws_service_access_principals = ["guardduty.${data.aws_partition.current.dns_suffix}"] + feature_set = "ALL" +} + +resource "aws_guardduty_detector" "test" {} + +resource "aws_guardduty_organization_admin_account" "test" { + depends_on = [aws_organizations_organization.test] + + admin_account_id = data.aws_caller_identity.current.account_id +} + +resource "aws_guardduty_organization_configuration" "test" { + depends_on = [aws_guardduty_organization_admin_account.test] + + auto_enable = true + detector_id = aws_guardduty_detector.test.id + + datasources { + s3_logs { + auto_enable = %[1]t + } + } +} +`, autoEnable) +} diff --git a/aws/resource_aws_guardduty_test.go b/aws/resource_aws_guardduty_test.go index 596655cb7aa..fe042b6bea7 100644 --- a/aws/resource_aws_guardduty_test.go +++ b/aws/resource_aws_guardduty_test.go @@ -30,7 +30,8 @@ func TestAccAWSGuardDuty_serial(t *testing.T) { "basic": testAccAwsGuardDutyOrganizationAdminAccount_basic, }, "OrganizationConfiguration": { - "basic": testAccAwsGuardDutyOrganizationConfiguration_basic, + "basic": testAccAwsGuardDutyOrganizationConfiguration_basic, + "s3Logs": testAccAwsGuardDutyOrganizationConfiguration_s3logs, }, "ThreatIntelSet": { "basic": testAccAwsGuardDutyThreatintelset_basic, diff --git a/website/docs/r/guardduty_organization_configuration.html.markdown b/website/docs/r/guardduty_organization_configuration.html.markdown index b972f04cddb..6a44a467b31 100644 --- a/website/docs/r/guardduty_organization_configuration.html.markdown +++ b/website/docs/r/guardduty_organization_configuration.html.markdown @@ -22,6 +22,12 @@ resource "aws_guardduty_detector" "example" { resource "aws_guardduty_organization_configuration" "example" { auto_enable = true detector_id = aws_guardduty_detector.example.id + + datasources { + s3_logs { + auto_enable = true + } + } } ``` @@ -31,6 +37,16 @@ The following arguments are supported: * `auto_enable` - (Required) When this setting is enabled, all new accounts that are created in, or added to, the organization are added as a member accounts of the organization’s GuardDuty delegated administrator and GuardDuty is enabled in that AWS Region. * `detector_id` - (Required) The detector ID of the GuardDuty account. +* `datasources` - (Optional) Configuration for the collected datasources. + +`datasources` supports the following: + +* `s3_logs` - (Optional) Configuration for the builds to store logs to S3. + +`s3_logs` supports the following: + +* `auto_enable` - (Optional) Set to `true` if you want S3 data event logs to be automatically enabled for new members of the organization. Default: `false` + ## Attributes Reference