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

d/aws_securityhub_standards_control_associations: new data source #39334

Merged
3 changes: 3 additions & 0 deletions .changelog/39334.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_securityhub_standards_control_associations
```
3 changes: 3 additions & 0 deletions internal/service/securityhub/securityhub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ func TestAccSecurityHub_serial(t *testing.T) {
"DisabledControlStatus": testAccStandardsControl_disabledControlStatus,
"EnabledControlStatusAndDisabledReason": testAccStandardsControl_enabledControlStatusAndDisabledReason,
},
"StandardsControlAssociationsDataSource": {
acctest.CtBasic: testAccStandardsControlAssociationsDataSource_basic,
},
"StandardsSubscription": {
acctest.CtBasic: testAccStandardsSubscription_basic,
acctest.CtDisappears: testAccStandardsSubscription_disappears,
Expand Down
7 changes: 6 additions & 1 deletion internal/service/securityhub/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package securityhub

import (
"context"

"github.com/aws/aws-sdk-go-v2/service/securityhub"
awstypes "github.com/aws/aws-sdk-go-v2/service/securityhub/types"
"github.com/hashicorp/aws-sdk-go-base/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkDataSource(name=Standards Control Associations)
func newDataSourceStandardsControlAssociations(context.Context) (datasource.DataSourceWithConfigure, error) {
d := &dataSourceStandardsControlAssociations{}

return d, nil
}

const (
DSNameStandardsControlAssociations = "Standards Control Associations Data Source"
)

type dataSourceStandardsControlAssociations struct {
framework.DataSourceWithConfigure
}

func (d *dataSourceStandardsControlAssociations) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
response.TypeName = "aws_securityhub_standards_control_associations"
}

func (d *dataSourceStandardsControlAssociations) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
names.AttrID: framework.IDAttribute(),
"security_control_id": schema.StringAttribute{
Required: true,
},
},
Blocks: map[string]schema.Block{
"standards_control_associations": schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[standardsControlAssociationData](ctx),
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"association_status": schema.StringAttribute{
CustomType: fwtypes.StringEnumType[awstypes.AssociationStatus](),
Computed: true,
},
"related_requirements": schema.ListAttribute{
CustomType: fwtypes.ListOfStringType,
ElementType: types.StringType,
Computed: true,
},
"security_control_arn": schema.StringAttribute{
Computed: true,
},
"security_control_id": schema.StringAttribute{
Computed: true,
},
"standards_arn": schema.StringAttribute{
Computed: true,
},
"standards_control_description": schema.StringAttribute{
Computed: true,
},
"standards_control_title": schema.StringAttribute{
Computed: true,
},
"updated_at": schema.StringAttribute{
CustomType: timetypes.RFC3339Type{},
Computed: true,
},
"updated_reason": schema.StringAttribute{
Computed: true,
},
},
},
},
},
}
}

func (d *dataSourceStandardsControlAssociations) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data dataSourceStandardsControlAssociationsData
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

conn := d.Meta().SecurityHubClient(ctx)

input := &securityhub.ListStandardsControlAssociationsInput{
SecurityControlId: data.SecurityControlID.ValueStringPointer(),
}

out, err := findStandardsControlAssociations(ctx, conn, input)

if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DevOpsGuru, create.ErrActionReading, DSNameStandardsControlAssociations, data.SecurityControlID.String(), err),
err.Error(),
)
return
}

data.ID = types.StringValue(d.Meta().Region)
resp.Diagnostics.Append(flex.Flatten(ctx, out, &data.StandardsControlAssociations)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

type dataSourceStandardsControlAssociationsData struct {
ID types.String `tfsdk:"id"`
SecurityControlID types.String `tfsdk:"security_control_id"`
StandardsControlAssociations fwtypes.ListNestedObjectValueOf[standardsControlAssociationData] `tfsdk:"standards_control_associations"`
}

type standardsControlAssociationData struct {
AssociationStatus fwtypes.StringEnum[awstypes.AssociationStatus] `tfsdk:"association_status"`
RelatedRequirements fwtypes.ListValueOf[types.String] `tfsdk:"related_requirements"`
SecurityControlARN types.String `tfsdk:"security_control_arn"`
SecurityControlID types.String `tfsdk:"security_control_id"`
StandardsARN types.String `tfsdk:"standards_arn"`
StandardsControlDescription types.String `tfsdk:"standards_control_description"`
StandardsControlTitle types.String `tfsdk:"standards_control_title"`
UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at"`
UpdatedReason types.String `tfsdk:"updated_reason"`
}

func findStandardsControlAssociations(ctx context.Context, conn *securityhub.Client, input *securityhub.ListStandardsControlAssociationsInput) ([]awstypes.StandardsControlAssociationSummary, error) {
var output []awstypes.StandardsControlAssociationSummary

pages := securityhub.NewListStandardsControlAssociationsPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)

if tfawserr.ErrCodeEquals(err, errCodeResourceNotFoundException) || tfawserr.ErrMessageContains(err, errCodeInvalidAccessException, "not subscribed to AWS Security Hub") {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

output = append(output, page.StandardsControlAssociationSummaries...)
}

return output, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package securityhub_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/names"
)

func testAccStandardsControlAssociationsDataSource_basic(t *testing.T) {
ctx := acctest.Context(t)
dataSourceName := "data.aws_securityhub_standards_control_associations.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SecurityHubServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: acctest.CheckDestroyNoop,
Steps: []resource.TestStep{
{
Config: testAccStandardsControlAssociationsDataSourceConfig_basic,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "standards_control_associations.#", acctest.Ct1),
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "standards_control_associations.*", map[string]string{
"association_status": "ENABLED",
"security_control_id": "IAM.1",
}),
),
},
},
})
}

const testAccStandardsControlAssociationsDataSourceConfig_basic = `
data "aws_partition" "current" {}

resource "aws_securityhub_account" "test" {
enable_default_standards = false
}

resource "aws_securityhub_standards_subscription" "test" {
standards_arn = "arn:${data.aws_partition.current.partition}:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0"

depends_on = [aws_securityhub_account.test]
}

data "aws_securityhub_standards_control_associations" "test" {
security_control_id = "IAM.1"

depends_on = [aws_securityhub_standards_subscription.test]
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
subcategory: "Security Hub"
layout: "aws"
page_title: "AWS: aws_securityhub_standards_control_associations"
description: |-
Terraform data source for managing an AWS Security Hub Standards Control Associations.
---

# Resource: aws_securityhub_standards_control_associations

Terraform data source for managing an AWS Security Hub Standards Control Associations.

## Example Usage

### Basic Usage

```terraform
resource "aws_securityhub_account" "test" {}

data "aws_securityhub_standards_control_associations" "test" {
security_control_id = "IAM.1"

depends_on = [aws_securityhub_account.test]
}
```

## Argument Reference

* `security_control_id` - (Required) The identifier of the control (identified with `SecurityControlId`, `SecurityControlArn`, or a mix of both parameters).

## Attribute Reference

This data source exports the following attributes in addition to the arguments above:

* `standards_control_associations` - A list that provides the status and other details for each security control that applies to each enabled standard.
See [`standards_control_associations`](#standards_control_associations-attribute-reference) below.

### `standards_control_associations` Attribute Reference

* `assocation_status` - Enablement status of a control in a specific standard.
* `related_requirements` - List of underlying requirements in the compliance framework related to the standard.
* `security_control_arn` - ARN of the security control.
* `security_control_id` - ID of the security control.
* `standards_arn` - ARN of the standard.
* `standards_control_description` - Description of the standard.
* `standards_control_title` - Title of the standard.
* `updated_at` - Last time that a control's enablement status in a specified standard was updated.
* `updated_reason` - Reason for updating a control's enablement status in a specified standard.
Loading