-
Notifications
You must be signed in to change notification settings - Fork 9.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
r/aws_fms_admin_account: New resource
- Loading branch information
Showing
5 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/fms" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceAwsFmsAdminAccount() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceAwsFmsAdminAccountPut, | ||
Read: resourceAwsFmsAdminAccountRead, | ||
Delete: resourceAwsFmsAdminAccountDelete, | ||
|
||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Timeouts: &schema.ResourceTimeout{ | ||
Create: schema.DefaultTimeout(1 * time.Minute), | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"account_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
ValidateFunc: validateAwsAccountId, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsFmsAdminAccountPut(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).fmsconn | ||
|
||
accountId := meta.(*AWSClient).accountid | ||
if v, ok := d.GetOk("account_id"); ok && v != "" { | ||
accountId = v.(string) | ||
} | ||
|
||
stateConf := &resource.StateChangeConf{ | ||
Target: []string{accountId}, | ||
Refresh: associateAdminAccountRefreshFunc(conn, accountId), | ||
Timeout: d.Timeout(schema.TimeoutCreate), | ||
Delay: 10 * time.Second, | ||
MinTimeout: 3 * time.Second, | ||
} | ||
|
||
log.Printf("[DEBUG] Waiting for firewall manager admin account association: %v", accountId) | ||
_, sterr := stateConf.WaitForState() | ||
if sterr != nil { | ||
return fmt.Errorf("Error waiting for firewall manager admin account association (%s): %s", accountId, sterr) | ||
} | ||
|
||
d.SetId(accountId) | ||
return nil | ||
} | ||
|
||
func associateAdminAccountRefreshFunc(conn *fms.FMS, accountId string) resource.StateRefreshFunc { | ||
// This is all wrapped in a refresh func since AssociateAdminAccount returns | ||
// success even though it failed if called too quickly after creating an organization | ||
return func() (interface{}, string, error) { | ||
req := &fms.AssociateAdminAccountInput{ | ||
AdminAccount: aws.String(accountId), | ||
} | ||
|
||
_, aserr := conn.AssociateAdminAccount(req) | ||
if aserr != nil { | ||
return nil, "", aserr | ||
} | ||
|
||
res, err := conn.GetAdminAccount(&fms.GetAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
return nil, "", nil | ||
} | ||
return nil, "", err | ||
} | ||
return *res, *res.AdminAccount, err | ||
} | ||
} | ||
|
||
func resourceAwsFmsAdminAccountRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).fmsconn | ||
|
||
res, err := conn.GetAdminAccount(&fms.GetAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
log.Printf("[WARN] No associated firewall manager admin account found, removing from state: %s", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
if d.Id() != aws.StringValue(res.AdminAccount) { | ||
log.Printf("[WARN] FMS Admin Account does not match, removing from state: %s", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("account_id", res.AdminAccount) | ||
return nil | ||
} | ||
|
||
func resourceAwsFmsAdminAccountDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).fmsconn | ||
|
||
_, err := conn.DisassociateAdminAccount(&fms.DisassociateAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
log.Printf("[WARN] No associated firewall manager admin account found, removing from state: %s", d.Id()) | ||
return nil | ||
} | ||
return fmt.Errorf("Error disassociating firewall manager admin account: %s", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/service/fms" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func init() { | ||
resource.AddTestSweepers("aws_fms_admin_account", &resource.Sweeper{ | ||
Name: "aws_fms_admin_account", | ||
F: testSweepFmsAdminAccount, | ||
}) | ||
} | ||
|
||
func testSweepFmsAdminAccount(region string) error { | ||
client, err := sharedClientForRegion(region) | ||
if err != nil { | ||
return fmt.Errorf("Error getting client: %s", err) | ||
} | ||
conn := client.(*AWSClient).fmsconn | ||
|
||
_, err = conn.GetAdminAccount(&fms.GetAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
log.Print("[DEBUG] No associated firewall manager admin account to sweep") | ||
return nil | ||
} | ||
return fmt.Errorf("Error retrieving firewall manager admin account: %s", err) | ||
} | ||
|
||
_, err = conn.DisassociateAdminAccount(&fms.DisassociateAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
log.Print("[DEBUG] No associated firewall manager admin account to sweep") | ||
return nil | ||
} | ||
return fmt.Errorf("Error disassociating firewall manager admin account: %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func TestAccFmsAdminAccount_basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckFmsAdminAccountDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccFmsAdminAccountConfig_basic, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestMatchResourceAttr("aws_fms_admin_account.example", "account_id", regexp.MustCompile("^\\d{12}$")), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckFmsAdminAccountDestroy(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*AWSClient).fmsconn | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "aws_fms_admin_account" { | ||
continue | ||
} | ||
|
||
res, err := conn.GetAdminAccount(&fms.GetAdminAccountInput{}) | ||
if err != nil { | ||
// FMS returns an AccessDeniedException if no account is associated, | ||
// but does not define this in its error codes | ||
if isAWSErr(err, "AccessDeniedException", "is not currently delegated by AWS FM") { | ||
log.Print("[DEBUG] No associated firewall manager admin account") | ||
return nil | ||
} | ||
} | ||
|
||
return fmt.Errorf("Firewall manager admin account still exists: %v", res.AdminAccount) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
const testAccFmsAdminAccountConfig_basic = ` | ||
provider "aws" { | ||
region = "us-east-1" | ||
} | ||
resource "aws_fms_admin_account" "example" { | ||
depends_on = ["aws_organizations_organization.example"] | ||
account_id = "${data.aws_caller_identity.current.account_id}" # Required | ||
} | ||
resource "aws_organizations_organization" "example" { | ||
feature_set = "ALL" | ||
} | ||
data "aws_caller_identity" "current" {} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
layout: "aws" | ||
page_title: "AWS: aws_fms_admin_account" | ||
sidebar_current: "docs-aws-fms-admin-account" | ||
description: |- | ||
Provides a resource to associate/disassociate an AWS Firewall Manager administrator account | ||
--- | ||
|
||
# aws_fms_admin_account | ||
|
||
-> **Note:** There is only a single Firewall Manager administator account allowed per AWS account. Any existing administrator account will be lost when using this resource as an effect of this limitation. | ||
|
||
Provides a resource to associate/disassociate an AWS Firewall Manager administrator account. | ||
|
||
```hcl | ||
resource "aws_fms_admin_account" "example" { | ||
account_id = "123456789012" # Required | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `account_id` - (Required) The AWS account ID to associate with AWS Firewall Manager as the AWS Firewall Manager administrator account. This can be an AWS Organizations master account or a member account. | ||
|
||
## Import | ||
|
||
Firewall Manager administrator account association can be imported using the account ID, e.g. | ||
|
||
``` | ||
$ terraform import aws_fms_admin_account.example 123456789012 | ||
``` |