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

r/aws_securityhub: Add aws_securityhub_standards_subscription #6862

Merged
merged 2 commits into from
Dec 19, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ func Provider() terraform.ResourceProvider {
"aws_default_security_group": resourceAwsDefaultSecurityGroup(),
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
"aws_securityhub_account": resourceAwsSecurityHubAccount(),
"aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(),
"aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(),
"aws_service_discovery_private_dns_namespace": resourceAwsServiceDiscoveryPrivateDnsNamespace(),
"aws_service_discovery_public_dns_namespace": resourceAwsServiceDiscoveryPublicDnsNamespace(),
Expand Down
93 changes: 93 additions & 0 deletions aws/resource_aws_securityhub_standards_subscription.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsSecurityHubStandardsSubscription() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSecurityHubStandardsSubscriptionCreate,
Read: resourceAwsSecurityHubStandardsSubscriptionRead,
Delete: resourceAwsSecurityHubStandardsSubscriptionDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"standards_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateArn,
},
},
}
}

func resourceAwsSecurityHubStandardsSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).securityhubconn
log.Printf("[DEBUG] Enabling Security Hub standard %s", d.Get("standards_arn"))

resp, err := conn.BatchEnableStandards(&securityhub.BatchEnableStandardsInput{
StandardsSubscriptionRequests: []*securityhub.StandardsSubscriptionRequest{
{
StandardsArn: aws.String(d.Get("standards_arn").(string)),
},
},
})

if err != nil {
return fmt.Errorf("Error enabling Security Hub standard: %s", err)
}

standardsSubscription := resp.StandardsSubscriptions[0]

d.SetId(*standardsSubscription.StandardsSubscriptionArn)

return resourceAwsSecurityHubStandardsSubscriptionRead(d, meta)
}

func resourceAwsSecurityHubStandardsSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).securityhubconn

log.Printf("[DEBUG] Reading Security Hub standard %s", d.Id())
resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{
StandardsSubscriptionArns: []*string{aws.String(d.Id())},
})

if err != nil {
return fmt.Errorf("Error reading Security Hub standard %s: %s", d.Id(), err)
}

if len(resp.StandardsSubscriptions) == 0 {
log.Printf("[WARN] Security Hub standard (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

standardsSubscription := resp.StandardsSubscriptions[0]

d.Set("standards_arn", standardsSubscription.StandardsArn)

return nil
}

func resourceAwsSecurityHubStandardsSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).securityhubconn
log.Printf("[DEBUG] Disabling Security Hub standard %s", d.Id())

_, err := conn.BatchDisableStandards(&securityhub.BatchDisableStandardsInput{
StandardsSubscriptionArns: []*string{aws.String(d.Id())},
})

if err != nil {
return fmt.Errorf("Error disabling Security Hub standard %s: %s", d.Id(), err)
}

return nil
}
108 changes: 108 additions & 0 deletions aws/resource_aws_securityhub_standards_subscription_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package aws

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) {
var standardsSubscription *securityhub.StandardsSubscription

resource.Test(t, resource.TestCase{
bflad marked this conversation as resolved.
Show resolved Hide resolved
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityHubStandardsSubscriptionExists("aws_securityhub_standards_subscription.example", standardsSubscription),
),
},
{
ResourceName: "aws_securityhub_standards_subscription.example",
ImportState: true,
ImportStateVerify: true,
},
{
// Check Destroy - but only target the specific resource (otherwise Security Hub
bflad marked this conversation as resolved.
Show resolved Hide resolved
// will be disabled and the destroy check will fail)
Config: testAccAWSSecurityHubStandardsSubscriptionConfig_empty,
Check: testAccCheckAWSSecurityHubStandardsSubscriptionDestroy,
},
},
})
}

func testAccCheckAWSSecurityHubStandardsSubscriptionExists(n string, standardsSubscription *securityhub.StandardsSubscription) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

conn := testAccProvider.Meta().(*AWSClient).securityhubconn

resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{
StandardsSubscriptionArns: []*string{aws.String(rs.Primary.ID)},
})

if err != nil {
return err
}

if len(resp.StandardsSubscriptions) == 0 {
return fmt.Errorf("Security Hub standard %s not found", rs.Primary.ID)
}

standardsSubscription = resp.StandardsSubscriptions[0]

return nil
}
}

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

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_securityhub_standards_subscription" {
continue
}

resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{
StandardsSubscriptionArns: []*string{aws.String(rs.Primary.ID)},
})

if err != nil {
if isAWSErr(err, securityhub.ErrCodeResourceNotFoundException, "") {
return nil
bflad marked this conversation as resolved.
Show resolved Hide resolved
}
return err
}

if len(resp.StandardsSubscriptions) != 0 {
return fmt.Errorf("Security Hub standard %s still exists", rs.Primary.ID)
}

return nil
bflad marked this conversation as resolved.
Show resolved Hide resolved
}

return nil
}

const testAccAWSSecurityHubStandardsSubscriptionConfig_empty = `
resource "aws_securityhub_account" "example" {}
`

const testAccAWSSecurityHubStandardsSubscriptionConfig_basic = `
resource "aws_securityhub_account" "example" {}

resource "aws_securityhub_standards_subscription" "example" {
depends_on = ["aws_securityhub_account.example"]
standards_arn = "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0"
}
`
3 changes: 3 additions & 0 deletions aws/resource_aws_securityhub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ func TestAccAWSSecurityHub(t *testing.T) {
"Account": {
"basic": testAccAWSSecurityHubAccount_basic,
},
"StandardsSubscription": {
"basic": testAccAWSSecurityHubStandardsSubscription_basic,
},
}

for group, m := range testCases {
Expand Down
4 changes: 4 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2187,6 +2187,10 @@
<a href="/docs/providers/aws/r/securityhub_account.html">aws_securityhub_account</a>
</li>

<li<%= sidebar_current("docs-aws-resource-securityhub-standards-subscription") %>>
<a href="/docs/providers/aws/r/securityhub_standards_subscription.html">aws_securityhub_standards_subscription</a>
</li>

</ul>
</li>

Expand Down
48 changes: 48 additions & 0 deletions website/docs/r/securityhub_standards_subscription.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
layout: "aws"
page_title: "AWS: aws_securityhub_standards_subscription"
sidebar_current: "docs-aws-resource-securityhub-standards-subscription"
description: |-
Subscribes to a Security Hub standard.
---

# aws_securityhub_standards_subscription

Subscribes to a Security Hub standard.

## Example Usage

```hcl
resource "aws_securityhub_account" "example" {}

resource "aws_securityhub_standards_subscription" "example" {
depends_on = ["aws_securityhub_account.example"]
standards_arn = "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0"
}
```

## Argument Reference

The following arguments are supported:

* `standards_arn` - (Required) The ARN of a standard - see below.

Currently available standards:

| Name | ARN |
|---------------------|-----------------------------------------------------------------------|
| CIS AWS Foundations | `arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0` |

## Attributes Reference

The following attributes are exported in addition to the arguments listed above:

* `id` - The ARN of a resource that represents your subscription to a supported standard.

## Import

Security Hub standards subscriptions can be imported using the standards subscription ARN, e.g.

```
$ terraform import aws_securityhub_standards_subscription.example arn:aws:securityhub:eu-west-1:123456789012:subscription/cis-aws-foundations-benchmark/v/1.2.0
```