From b861fe8ebfb2d3862e9ca2bd38ccbeafbd3fd01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 5 Sep 2019 10:08:53 +0200 Subject: [PATCH 01/10] add aws_security_hub_member resource --- aws/provider.go | 1 + aws/resource_aws_securityhub_member.go | 111 +++++++++++++++++++++++++ main.go | 2 +- 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 aws/resource_aws_securityhub_member.go diff --git a/aws/provider.go b/aws/provider.go index 6cdba7a4e5a..77666a46d2a 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -698,6 +698,7 @@ func Provider() terraform.ResourceProvider { "aws_default_security_group": resourceAwsDefaultSecurityGroup(), "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_securityhub_account": resourceAwsSecurityHubAccount(), + "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), diff --git a/aws/resource_aws_securityhub_member.go b/aws/resource_aws_securityhub_member.go new file mode 100644 index 00000000000..da47c9216b4 --- /dev/null +++ b/aws/resource_aws_securityhub_member.go @@ -0,0 +1,111 @@ +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 resourceAwsSecurityHubMember() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSecurityHubMemberCreate, + Read: resourceAwsSecurityHubMemberRead, + Delete: resourceAwsSecurityHubMemberDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "email": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "master_id": { + Type: schema.TypeString, + Computed: true, + }, + "member_status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsSecurityHubMemberCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + accountId := d.Get("account_id").(string) + + log.Printf("[DEBUG] Adding %s to Security Hub", accountId) + + _, err := conn.CreateMembers(&securityhub.CreateMembersInput{ + AccountDetails: []*securityhub.AccountDetails{ + { + AccountId: aws.String(accountId), + Email: aws.String(d.Get("email").(string)), + }, + }, + }) + + if err != nil { + return fmt.Errorf("Error adding %s to Security Hub: %s", accountId, err) + } + + d.SetId(accountId) + + return resourceAwsSecurityHubMemberRead(d, meta) +} + +func resourceAwsSecurityHubMemberRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + log.Printf("[DEBUG] Retrieving members of Security Hub for account %s", d.Id()) + resp, err := conn.GetMembers(&securityhub.GetMembersInput{ + AccountIds: []*string{ + aws.String(d.Id()), + }, + }) + + if err != nil { + return fmt.Errorf("Error retrieving members of Security Hub for account %s: %s", d.Id(), err) + } + + // This means that this account is not associated anymore + if len(resp.Members) == 0 { + d.SetId("") + return nil + } + + member := resp.Members[0] + + d.Set("master_id", member.MasterId) + d.Set("member_status", member.MemberStatus) + + return nil +} + +func resourceAwsSecurityHubMemberDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + log.Printf("[DEBUG] Deleting %s from Security Hub", d.Id()) + + _, err := conn.DeleteMembers(&securityhub.DeleteMembersInput{ + AccountIds: []*string{ + aws.String(d.Id()), + }, + }) + + if err != nil { + return fmt.Errorf("Error deleting %s from Security Hub: %s", d.Id(), err) + } + + return nil +} diff --git a/main.go b/main.go index 4d56a352b8d..12239aedf32 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,7 @@ package main import ( "github.com/hashicorp/terraform/plugin" - "github.com/terraform-providers/terraform-provider-aws/aws" + "github.com/kamsz/terraform-provider-aws/aws" ) func main() { From 141bdae829705dd6629e4ab728abc3c85df50cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 5 Sep 2019 11:22:00 +0200 Subject: [PATCH 02/10] aws_securityhub_invite and aws_securityhub_accept_invitation resources --- aws/provider.go | 2 + ...ource_aws_securityhub_accept_invitation.go | 86 ++++++++++++++++++ aws/resource_aws_securityhub_invite.go | 89 +++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 aws/resource_aws_securityhub_accept_invitation.go create mode 100644 aws/resource_aws_securityhub_invite.go diff --git a/aws/provider.go b/aws/provider.go index 77666a46d2a..c1f2604a055 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -698,6 +698,8 @@ func Provider() terraform.ResourceProvider { "aws_default_security_group": resourceAwsDefaultSecurityGroup(), "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_securityhub_account": resourceAwsSecurityHubAccount(), + "aws_securityhub_accept_invitation": resourceAwsSecurityHubAcceptInvitation(), + "aws_securityhub_invite": resourceAwsSecurityHubInvite(), "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), diff --git a/aws/resource_aws_securityhub_accept_invitation.go b/aws/resource_aws_securityhub_accept_invitation.go new file mode 100644 index 00000000000..6328fedbb55 --- /dev/null +++ b/aws/resource_aws_securityhub_accept_invitation.go @@ -0,0 +1,86 @@ +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 resourceAwsSecurityHubAcceptInvitation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSecurityHubAcceptInvitationCreate, + Read: resourceAwsSecurityHubAcceptInvitationRead, + Delete: resourceAwsSecurityHubAcceptInvitationDelete, + + Schema: map[string]*schema.Schema{ + "master_account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsSecurityHubAcceptInvitationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + log.Print("[DEBUG] Retrieving list of invitations") + + resp, err := conn.ListInvitations(&securityhub.ListInvitationsInput{}) + + if err != nil { + return fmt.Errorf("Error retrieving Security Hub invitations list: %s", err) + } + + masterAccountId := d.Get("master_account_id").(string) + + log.Printf("[DEBUG] Accepting invitation to Security Hub from %s", masterAccountId) + + for i := range resp.Invitations { + if *resp.Invitations[i].AccountId == masterAccountId { + _, err := conn.AcceptInvitation(&securityhub.AcceptInvitationInput{ + MasterId: aws.String(masterAccountId), + InvitationId: resp.Invitations[i].InvitationId, + }) + + if err != nil { + return fmt.Errorf("Error accepting invite to Security Hub from %s: %s", masterAccountId, err) + } + + d.SetId(*resp.Invitations[i].InvitationId) + } + } + + return nil +} + +func resourceAwsSecurityHubAcceptInvitationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + log.Print("[DEBUG] Retrieving list of invitations") + + resp, err := conn.ListInvitations(&securityhub.ListInvitationsInput{}) + + if err != nil { + return fmt.Errorf("Error retrieving Security Hub invitations list: %s", err) + } + + for i := range resp.Invitations { + if *resp.Invitations[i].AccountId == d.Get("master_account_id").(string) { + d.SetId(*resp.Invitations[i].InvitationId) + return nil + } + } + + d.SetId("") + return nil +} + +func resourceAwsSecurityHubAcceptInvitationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARN] Will not delete Security Hub invitation. Terraform will remove this resource from the state file, however resources may remain.") + return nil +} diff --git a/aws/resource_aws_securityhub_invite.go b/aws/resource_aws_securityhub_invite.go new file mode 100644 index 00000000000..ea2b4633041 --- /dev/null +++ b/aws/resource_aws_securityhub_invite.go @@ -0,0 +1,89 @@ +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 resourceAwsSecurityHubInvite() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSecurityHubInviteCreate, + Read: resourceAwsSecurityHubInviteRead, + Delete: resourceAwsSecurityHubInviteDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsSecurityHubInviteCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + accountId := d.Get("account_id").(string) + + log.Printf("[DEBUG] Inviting %s to Security Hub", accountId) + + _, err := conn.InviteMembers(&securityhub.InviteMembersInput{ + AccountIds: []*string{ + aws.String(accountId), + }, + }) + + if err != nil { + return fmt.Errorf("Error inviting %s to Security Hub: %s", accountId, err) + } + + d.SetId(accountId) + + return resourceAwsSecurityHubInviteRead(d, meta) +} + +func resourceAwsSecurityHubInviteRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + log.Printf("[DEBUG] Retrieving members of Security Hub for account %s", d.Id()) + membersResp, err := conn.GetMembers(&securityhub.GetMembersInput{ + AccountIds: []*string{ + aws.String(d.Id()), + }, + }) + + if err != nil { + return fmt.Errorf("Error retrieving members of Security Hub for account %s: %s", d.Id(), err) + } + + // This means that this account is not associated anymore + if len(membersResp.Members) == 0 { + d.SetId("") + } + + return nil +} + +func resourceAwsSecurityHubInviteDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + log.Printf("[DEBUG] Deleting invitation for %s from Security Hub", d.Id()) + + _, err := conn.DeleteInvitations(&securityhub.DeleteInvitationsInput{ + AccountIds: []*string{ + aws.String(d.Id()), + }, + }) + + if err != nil { + return fmt.Errorf("Error deleting invitation for %s from Security Hub: %s", d.Id(), err) + } + + return nil +} From c10cd986e503a5ed3d12e1c075b317bbc43624d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 5 Sep 2019 11:28:45 +0200 Subject: [PATCH 03/10] revert change to main.go --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 12239aedf32..4d56a352b8d 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,7 @@ package main import ( "github.com/hashicorp/terraform/plugin" - "github.com/kamsz/terraform-provider-aws/aws" + "github.com/terraform-providers/terraform-provider-aws/aws" ) func main() { From 17b322844601cf872a13f0f6f0f6030a5183f300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 5 Sep 2019 11:39:11 +0200 Subject: [PATCH 04/10] remove member/invite resources as they're already in different PR --- aws/provider.go | 2 - aws/resource_aws_securityhub_invite.go | 89 -------------------- aws/resource_aws_securityhub_member.go | 111 ------------------------- 3 files changed, 202 deletions(-) delete mode 100644 aws/resource_aws_securityhub_invite.go delete mode 100644 aws/resource_aws_securityhub_member.go diff --git a/aws/provider.go b/aws/provider.go index c1f2604a055..f6c29b48aae 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -699,8 +699,6 @@ func Provider() terraform.ResourceProvider { "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_securityhub_account": resourceAwsSecurityHubAccount(), "aws_securityhub_accept_invitation": resourceAwsSecurityHubAcceptInvitation(), - "aws_securityhub_invite": resourceAwsSecurityHubInvite(), - "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), diff --git a/aws/resource_aws_securityhub_invite.go b/aws/resource_aws_securityhub_invite.go deleted file mode 100644 index ea2b4633041..00000000000 --- a/aws/resource_aws_securityhub_invite.go +++ /dev/null @@ -1,89 +0,0 @@ -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 resourceAwsSecurityHubInvite() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsSecurityHubInviteCreate, - Read: resourceAwsSecurityHubInviteRead, - Delete: resourceAwsSecurityHubInviteDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - - Schema: map[string]*schema.Schema{ - "account_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - } -} - -func resourceAwsSecurityHubInviteCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - accountId := d.Get("account_id").(string) - - log.Printf("[DEBUG] Inviting %s to Security Hub", accountId) - - _, err := conn.InviteMembers(&securityhub.InviteMembersInput{ - AccountIds: []*string{ - aws.String(accountId), - }, - }) - - if err != nil { - return fmt.Errorf("Error inviting %s to Security Hub: %s", accountId, err) - } - - d.SetId(accountId) - - return resourceAwsSecurityHubInviteRead(d, meta) -} - -func resourceAwsSecurityHubInviteRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - - log.Printf("[DEBUG] Retrieving members of Security Hub for account %s", d.Id()) - membersResp, err := conn.GetMembers(&securityhub.GetMembersInput{ - AccountIds: []*string{ - aws.String(d.Id()), - }, - }) - - if err != nil { - return fmt.Errorf("Error retrieving members of Security Hub for account %s: %s", d.Id(), err) - } - - // This means that this account is not associated anymore - if len(membersResp.Members) == 0 { - d.SetId("") - } - - return nil -} - -func resourceAwsSecurityHubInviteDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - log.Printf("[DEBUG] Deleting invitation for %s from Security Hub", d.Id()) - - _, err := conn.DeleteInvitations(&securityhub.DeleteInvitationsInput{ - AccountIds: []*string{ - aws.String(d.Id()), - }, - }) - - if err != nil { - return fmt.Errorf("Error deleting invitation for %s from Security Hub: %s", d.Id(), err) - } - - return nil -} diff --git a/aws/resource_aws_securityhub_member.go b/aws/resource_aws_securityhub_member.go deleted file mode 100644 index da47c9216b4..00000000000 --- a/aws/resource_aws_securityhub_member.go +++ /dev/null @@ -1,111 +0,0 @@ -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 resourceAwsSecurityHubMember() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsSecurityHubMemberCreate, - Read: resourceAwsSecurityHubMemberRead, - Delete: resourceAwsSecurityHubMemberDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - - Schema: map[string]*schema.Schema{ - "account_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "email": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "master_id": { - Type: schema.TypeString, - Computed: true, - }, - "member_status": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceAwsSecurityHubMemberCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - accountId := d.Get("account_id").(string) - - log.Printf("[DEBUG] Adding %s to Security Hub", accountId) - - _, err := conn.CreateMembers(&securityhub.CreateMembersInput{ - AccountDetails: []*securityhub.AccountDetails{ - { - AccountId: aws.String(accountId), - Email: aws.String(d.Get("email").(string)), - }, - }, - }) - - if err != nil { - return fmt.Errorf("Error adding %s to Security Hub: %s", accountId, err) - } - - d.SetId(accountId) - - return resourceAwsSecurityHubMemberRead(d, meta) -} - -func resourceAwsSecurityHubMemberRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - - log.Printf("[DEBUG] Retrieving members of Security Hub for account %s", d.Id()) - resp, err := conn.GetMembers(&securityhub.GetMembersInput{ - AccountIds: []*string{ - aws.String(d.Id()), - }, - }) - - if err != nil { - return fmt.Errorf("Error retrieving members of Security Hub for account %s: %s", d.Id(), err) - } - - // This means that this account is not associated anymore - if len(resp.Members) == 0 { - d.SetId("") - return nil - } - - member := resp.Members[0] - - d.Set("master_id", member.MasterId) - d.Set("member_status", member.MemberStatus) - - return nil -} - -func resourceAwsSecurityHubMemberDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).securityhubconn - log.Printf("[DEBUG] Deleting %s from Security Hub", d.Id()) - - _, err := conn.DeleteMembers(&securityhub.DeleteMembersInput{ - AccountIds: []*string{ - aws.String(d.Id()), - }, - }) - - if err != nil { - return fmt.Errorf("Error deleting %s from Security Hub: %s", d.Id(), err) - } - - return nil -} From f4d99c6c4e1046b81a4553f1811f3f1f5b935ab5 Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sat, 21 Mar 2020 10:16:34 +0000 Subject: [PATCH 05/10] resource/aws_securityhub_invite_accepter: Renaming to aws_securityhub_invite_accepter (part I) --- ..._invitation.go => resource_aws_securityhub_invite_accepter.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename aws/{resource_aws_securityhub_accept_invitation.go => resource_aws_securityhub_invite_accepter.go} (100%) diff --git a/aws/resource_aws_securityhub_accept_invitation.go b/aws/resource_aws_securityhub_invite_accepter.go similarity index 100% rename from aws/resource_aws_securityhub_accept_invitation.go rename to aws/resource_aws_securityhub_invite_accepter.go From 7ee717cf2e5e189fe8dc1819b8720b29527ea9ef Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sat, 21 Mar 2020 10:18:19 +0000 Subject: [PATCH 06/10] resource/aws_securityhub_invite_accepter: Renaming to aws_securityhub_invite_accepter (part II) --- ...esource_aws_securityhub_invite_accepter.go | 109 ++++++++++++------ 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_securityhub_invite_accepter.go b/aws/resource_aws_securityhub_invite_accepter.go index 6328fedbb55..d1f1c804a73 100644 --- a/aws/resource_aws_securityhub_invite_accepter.go +++ b/aws/resource_aws_securityhub_invite_accepter.go @@ -9,78 +9,115 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) -func resourceAwsSecurityHubAcceptInvitation() *schema.Resource { +func resourceAwsSecurityHubInviteAccepter() *schema.Resource { return &schema.Resource{ - Create: resourceAwsSecurityHubAcceptInvitationCreate, - Read: resourceAwsSecurityHubAcceptInvitationRead, - Delete: resourceAwsSecurityHubAcceptInvitationDelete, + Create: resourceAwsSecurityHubInviteAccepterCreate, + Read: resourceAwsSecurityHubInviteAccepterRead, + Delete: resourceAwsSecurityHubInviteAccepterDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ - "master_account_id": { + "master_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + + "invitation_id": { + Type: schema.TypeString, + Computed: true, + }, }, } } -func resourceAwsSecurityHubAcceptInvitationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsSecurityHubInviteAccepterCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).securityhubconn + log.Print("[DEBUG] Accepting Security Hub invitation") - log.Print("[DEBUG] Retrieving list of invitations") + invitationId, err := resourceAwsSecurityHubInviteAccepterGetInvitationId(conn, d.Get("master_id").(string)) - resp, err := conn.ListInvitations(&securityhub.ListInvitationsInput{}) + if err != nil { + return err + } + + _, err = conn.AcceptInvitation(&securityhub.AcceptInvitationInput{ + InvitationId: aws.String(invitationId), + MasterId: aws.String(d.Get("master_id").(string)), + }) if err != nil { - return fmt.Errorf("Error retrieving Security Hub invitations list: %s", err) + return fmt.Errorf("Error accepting Security Hub invitation: %s", err) } - masterAccountId := d.Get("master_account_id").(string) + d.SetId("securityhub-invitation-accepter") - log.Printf("[DEBUG] Accepting invitation to Security Hub from %s", masterAccountId) + return resourceAwsSecurityHubInviteAccepterRead(d, meta) +} + +func resourceAwsSecurityHubInviteAccepterGetInvitationId(conn *securityhub.SecurityHub, masterId string) (string, error) { + log.Printf("[DEBUG] Getting InvitationId for MasterId %s", masterId) - for i := range resp.Invitations { - if *resp.Invitations[i].AccountId == masterAccountId { - _, err := conn.AcceptInvitation(&securityhub.AcceptInvitationInput{ - MasterId: aws.String(masterAccountId), - InvitationId: resp.Invitations[i].InvitationId, - }) + resp, err := conn.ListInvitations(&securityhub.ListInvitationsInput{}) - if err != nil { - return fmt.Errorf("Error accepting invite to Security Hub from %s: %s", masterAccountId, err) - } + if err != nil { + return "", fmt.Errorf("Error listing Security Hub invitations: %s", err) + } - d.SetId(*resp.Invitations[i].InvitationId) + for _, invitation := range resp.Invitations { + log.Printf("[DEBUG] Invitation: %s", invitation) + if *invitation.AccountId == masterId { + return *invitation.InvitationId, nil } } - return nil + return "", fmt.Errorf("Cannot find InvitationId for MasterId %s", masterId) } -func resourceAwsSecurityHubAcceptInvitationRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsSecurityHubInviteAccepterRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).securityhubconn + log.Print("[DEBUG] Reading Security Hub master account") - log.Print("[DEBUG] Retrieving list of invitations") - - resp, err := conn.ListInvitations(&securityhub.ListInvitationsInput{}) + resp, err := conn.GetMasterAccount(&securityhub.GetMasterAccountInput{}) if err != nil { - return fmt.Errorf("Error retrieving Security Hub invitations list: %s", err) - } - - for i := range resp.Invitations { - if *resp.Invitations[i].AccountId == d.Get("master_account_id").(string) { - d.SetId(*resp.Invitations[i].InvitationId) + if isAWSErr(err, securityhub.ErrCodeResourceNotFoundException, "") { + log.Print("[WARN] Security Hub master account not found, removing from state") + d.SetId("") return nil } + return err + } + + master := resp.Master + + if master == nil { + log.Print("[WARN] Security Hub master account not found, removing from state") + d.SetId("") + return nil } - d.SetId("") + d.Set("invitation_id", master.InvitationId) + d.Set("master_id", master.AccountId) + return nil } -func resourceAwsSecurityHubAcceptInvitationDelete(d *schema.ResourceData, meta interface{}) error { - log.Printf("[WARN] Will not delete Security Hub invitation. Terraform will remove this resource from the state file, however resources may remain.") +func resourceAwsSecurityHubInviteAccepterDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + log.Print("[DEBUG] Disassociating from Security Hub master account") + + _, err := conn.DisassociateFromMasterAccount(&securityhub.DisassociateFromMasterAccountInput{}) + + if err != nil { + if isAWSErr(err, "BadRequestException", "The request is rejected because the current account is not associated to a master account") { + log.Print("[WARN] Security Hub account is not a member account") + return nil + } + return err + } + return nil -} +} \ No newline at end of file From 320ca1865e86bac2da4072bbaa9c2a3534ad1d18 Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sat, 21 Mar 2020 10:24:00 +0000 Subject: [PATCH 07/10] resource/aws_securityhub_invite_accepter: Add documentation --- .../r/securityhub_invite_accepter.markdown | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 website/docs/r/securityhub_invite_accepter.markdown diff --git a/website/docs/r/securityhub_invite_accepter.markdown b/website/docs/r/securityhub_invite_accepter.markdown new file mode 100644 index 00000000000..3915efc5f90 --- /dev/null +++ b/website/docs/r/securityhub_invite_accepter.markdown @@ -0,0 +1,54 @@ +--- +layout: "aws" +page_title: "AWS: aws_securityhub_invite_accepter" +sidebar_current: "docs-aws-resource-securityhub-invite-accepter" +description: |- + Accepts a Security Hub invitation. +--- + +# aws_securityhub_invite_accepter + +-> **Note:** AWS accounts can only be associated with a single Security Hub master account. Destroying this resource will disassociate the member account from the master account. + +Accepts a Security Hub invitation. + +## Example Usage + +```hcl +resource "aws_securityhub_account" "example" {} + +resource "aws_securityhub_member" "example" { + account_id = "123456789012" + email = "example@example.com" + invite = true +} + +resource "aws_securityhub_account" "invitee" { + provider = "aws.invitee" +} + +resource "aws_securityhub_invite_accepter" "invitee" { + provider = "aws.invitee" + master_id = "${aws_securityhub_member.example.master_id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `master_id` - (Required) The account ID of the master Security Hub account whose invitation you're accepting. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `id` - Returns `securityhub-invite-accepter`. + +## Import + +Security Hub invite acceptance can be imported using the word `securityhub-invite-accepter`, e.g. + +``` +$ terraform import aws_securityhub_invite_acceptor.example securityhub-invite-accepter +``` \ No newline at end of file From ce68255aba40786fc6694dd97b1618118a7a0d8f Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sat, 21 Mar 2020 10:27:09 +0000 Subject: [PATCH 08/10] resource/aws_securityhub_invite_accepter: Renaming to aws_securityhub_invite_accepter (part III) --- aws/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/provider.go b/aws/provider.go index d1082782247..d4c67849def 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -750,7 +750,7 @@ func Provider() terraform.ResourceProvider { "aws_default_security_group": resourceAwsDefaultSecurityGroup(), "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_securityhub_account": resourceAwsSecurityHubAccount(), - "aws_securityhub_accept_invitation": resourceAwsSecurityHubAcceptInvitation(), + "aws_securityhub_invite_accepter": resourceAwsSecurityHubInviteAccepter(), "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), From 1130ecb34bb2d520be874558b3a2e4ffbe07e8e4 Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sat, 21 Mar 2020 16:28:57 +0000 Subject: [PATCH 09/10] resource/aws_securityhub_invite_accepter: Add tests --- aws/provider_test.go | 10 ++ ...esource_aws_securityhub_invite_accepter.go | 4 +- ...ce_aws_securityhub_invite_acceptor_test.go | 115 ++++++++++++++++++ .../r/securityhub_invite_accepter.markdown | 5 +- 4 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 aws/resource_aws_securityhub_invite_acceptor_test.go diff --git a/aws/provider_test.go b/aws/provider_test.go index 63b57f08061..7b7da1f431c 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -343,6 +343,16 @@ func testAccAlternateAccountPreCheck(t *testing.T) { } } +func testAccGetAccountEmail() string { + return os.Getenv("AWS_EMAIL") +} + +func testAccAccountEmailPreCheck(t *testing.T) { + if os.Getenv("AWS_EMAIL") == "" { + t.Fatal("AWS_EMAIL must be set to the email address of the account used for acceptance tests") + } +} + func testAccAlternateRegionPreCheck(t *testing.T) { if testAccGetRegion() == testAccGetAlternateRegion() { t.Fatal("AWS_DEFAULT_REGION and AWS_ALTERNATE_REGION must be set to different values for acceptance tests") diff --git a/aws/resource_aws_securityhub_invite_accepter.go b/aws/resource_aws_securityhub_invite_accepter.go index d1f1c804a73..4b11dc2e4d7 100644 --- a/aws/resource_aws_securityhub_invite_accepter.go +++ b/aws/resource_aws_securityhub_invite_accepter.go @@ -6,7 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" - "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAwsSecurityHubInviteAccepter() *schema.Resource { @@ -120,4 +120,4 @@ func resourceAwsSecurityHubInviteAccepterDelete(d *schema.ResourceData, meta int } return nil -} \ No newline at end of file +} diff --git a/aws/resource_aws_securityhub_invite_acceptor_test.go b/aws/resource_aws_securityhub_invite_acceptor_test.go new file mode 100644 index 00000000000..963d7db5605 --- /dev/null +++ b/aws/resource_aws_securityhub_invite_acceptor_test.go @@ -0,0 +1,115 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSSecurityHubInviteAccepter_basic(t *testing.T) { + var providers []*schema.Provider + resourceName := "aws_securityhub_invite_accepter.example" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + testAccAccountEmailPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAWSSecurityHubInviteAccepterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSecurityHubInviteAccepterConfig_basic(testAccGetAccountEmail()), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSecurityHubInviteAccepterExists(resourceName), + ), + }, + { + Config: testAccAWSSecurityHubInviteAccepterConfig_basic(testAccGetAccountEmail()), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSSecurityHubInviteAccepterExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).securityhubconn + + resp, err := conn.GetMasterAccount(&securityhub.GetMasterAccountInput{}) + + if err != nil { + return err + } + + if resp == nil || resp.Master == nil || aws.StringValue(resp.Master.AccountId) == "" { + return fmt.Errorf("Security Hub master account found for: %s", resourceName) + } + + return nil + } +} + +func testAccCheckAWSSecurityHubInviteAccepterDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).securityhubconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_securityhub_invite_accepter" { + continue + } + + resp, err := conn.GetMasterAccount(&securityhub.GetMasterAccountInput{}) + + if err != nil { + if isAWSErr(err, securityhub.ErrCodeResourceNotFoundException, "") { + continue + } + return err + } + + if resp == nil || resp.Master == nil || aws.StringValue(resp.Master.AccountId) == "" { + continue + } + + return fmt.Errorf("Security Hub master account still configured: %s", aws.StringValue(resp.Master.AccountId)) + } + return nil +} + +func testAccAWSSecurityHubInviteAccepterConfig_basic(email string) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +resource "aws_securityhub_account" "example" { + provider = "aws.alternate" +} + +resource "aws_securityhub_member" "example" { + provider = "aws.alternate" + depends_on = [aws_securityhub_account.example] + account_id = data.aws_caller_identity.accepter.account_id + email = "%s" + invite = true +} + +data "aws_caller_identity" "accepter" {} + +resource "aws_securityhub_account" "accepter" {} + +resource "aws_securityhub_invite_accepter" "example" { + depends_on = [aws_securityhub_account.accepter] + master_id = aws_securityhub_member.example.master_id +} +`, email) +} diff --git a/website/docs/r/securityhub_invite_accepter.markdown b/website/docs/r/securityhub_invite_accepter.markdown index 3915efc5f90..56541f8e6b5 100644 --- a/website/docs/r/securityhub_invite_accepter.markdown +++ b/website/docs/r/securityhub_invite_accepter.markdown @@ -28,8 +28,9 @@ resource "aws_securityhub_account" "invitee" { } resource "aws_securityhub_invite_accepter" "invitee" { - provider = "aws.invitee" - master_id = "${aws_securityhub_member.example.master_id}" + provider = "aws.invitee" + depends_on = [aws_securityhub_account.accepter] + master_id = aws_securityhub_member.example.master_id } ``` From 93283f6d4b0cf310705f66520682b3f81da0eb9d Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Sun, 5 Apr 2020 14:50:51 +0100 Subject: [PATCH 10/10] resource/aws_securityhub_invite_accepter: Fix documentation --- website/aws.erb | 3 +++ website/docs/r/securityhub_invite_accepter.markdown | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/website/aws.erb b/website/aws.erb index b338883522c..0ee66b5f391 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -2754,6 +2754,9 @@
  • aws_securityhub_account
  • +
  • + aws_securityhub_invite_accepter +
  • aws_securityhub_member
  • diff --git a/website/docs/r/securityhub_invite_accepter.markdown b/website/docs/r/securityhub_invite_accepter.markdown index 56541f8e6b5..faf90ecbdae 100644 --- a/website/docs/r/securityhub_invite_accepter.markdown +++ b/website/docs/r/securityhub_invite_accepter.markdown @@ -1,7 +1,7 @@ --- +subcategory: "Security Hub" layout: "aws" page_title: "AWS: aws_securityhub_invite_accepter" -sidebar_current: "docs-aws-resource-securityhub-invite-accepter" description: |- Accepts a Security Hub invitation. ---