Skip to content

Commit

Permalink
Merge pull request #9594 from robh007/fms-policy
Browse files Browse the repository at this point in the history
r/aws_fms_policy: Add new resource for AWS Firewall Manager Policy
  • Loading branch information
bill-rich authored Jan 11, 2021
2 parents 3bd91cf + fe8440a commit bbefb8d
Show file tree
Hide file tree
Showing 4 changed files with 762 additions and 0 deletions.
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ func Provider() *schema.Provider {
"aws_fsx_lustre_file_system": resourceAwsFsxLustreFileSystem(),
"aws_fsx_windows_file_system": resourceAwsFsxWindowsFileSystem(),
"aws_fms_admin_account": resourceAwsFmsAdminAccount(),
"aws_fms_policy": resourceAwsFmsPolicy(),
"aws_gamelift_alias": resourceAwsGameliftAlias(),
"aws_gamelift_build": resourceAwsGameliftBuild(),
"aws_gamelift_fleet": resourceAwsGameliftFleet(),
Expand Down
347 changes: 347 additions & 0 deletions aws/resource_aws_fms_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,347 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/fms"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceAwsFmsPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsFmsPolicyCreate,
Read: resourceAwsFmsPolicyRead,
Update: resourceAwsFmsPolicyUpdate,
Delete: resourceAwsFmsPolicyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},

"delete_all_policy_resources": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},

"exclude_resource_tags": {
Type: schema.TypeBool,
Required: true,
},

"exclude_map": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
DiffSuppressFunc: suppressMissingOptionalConfigurationBlock,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"orgunit": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},

"include_map": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
DiffSuppressFunc: suppressMissingOptionalConfigurationBlock,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"orgunit": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},

"remediation_enabled": {
Type: schema.TypeBool,
Optional: true,
},

"resource_type_list": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{"AWS::ApiGateway::Stage", "AWS::ElasticLoadBalancingV2::LoadBalancer", "AWS::CloudFront::Distribution"}, false),
},
Set: schema.HashString,
},

"policy_update_token": {
Type: schema.TypeString,
Computed: true,
},

"resource_tags": tagsSchema(),

"security_service_policy_data": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Required: true,
},
"managed_service_data": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: suppressEquivalentJsonDiffs,
},
},
},
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

fmsPolicy := &fms.Policy{
PolicyName: aws.String(d.Get("name").(string)),
RemediationEnabled: aws.Bool(d.Get("remediation_enabled").(bool)),
ResourceType: aws.String("ResourceTypeList"),
ResourceTypeList: expandStringList(d.Get("resource_type_list").(*schema.Set).List()),
ExcludeResourceTags: aws.Bool(d.Get("exclude_resource_tags").(bool)),
}

securityServicePolicy := d.Get("security_service_policy_data").([]interface{})[0].(map[string]interface{})
fmsPolicy.SecurityServicePolicyData = &fms.SecurityServicePolicyData{
ManagedServiceData: aws.String(securityServicePolicy["managed_service_data"].(string)),
Type: aws.String(securityServicePolicy["type"].(string)),
}

if rTags, tagsOk := d.GetOk("resource_tags"); tagsOk {
fmsPolicy.ResourceTags = constructResourceTags(rTags)
}

if v, ok := d.GetOk("include_map"); ok {
fmsPolicy.IncludeMap = expandFMSPolicyMap(v.([]interface{}))
}

if v, ok := d.GetOk("exclude_map"); ok {
fmsPolicy.ExcludeMap = expandFMSPolicyMap(v.([]interface{}))
}

params := &fms.PutPolicyInput{
Policy: fmsPolicy,
}

var resp *fms.PutPolicyOutput
var err error

resp, err = conn.PutPolicy(params)

if err != nil {
return fmt.Errorf("Creating Policy Failed: %s", err.Error())
}

d.SetId(aws.StringValue(resp.Policy.PolicyId))

return resourceAwsFmsPolicyRead(d, meta)
}

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

var resp *fms.GetPolicyOutput
var req = &fms.GetPolicyInput{
PolicyId: aws.String(d.Id()),
}

resp, err := conn.GetPolicy(req)

if err != nil {
if isAWSErr(err, fms.ErrCodeResourceNotFoundException, "") {
log.Printf("[WARN] FMS Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
return err
}

d.Set("arn", aws.StringValue(resp.PolicyArn))

d.Set("name", aws.StringValue(resp.Policy.PolicyName))
d.Set("exclude_resource_tags", aws.BoolValue(resp.Policy.ExcludeResourceTags))
if err = d.Set("exclude_map", flattenFMSPolicyMap(resp.Policy.ExcludeMap)); err != nil {
return err
}
if err = d.Set("include_map", flattenFMSPolicyMap(resp.Policy.IncludeMap)); err != nil {
return err
}
d.Set("remediation_enabled", aws.BoolValue(resp.Policy.RemediationEnabled))
if err = d.Set("resource_type_list", resp.Policy.ResourceTypeList); err != nil {
return err
}
d.Set("policy_update_token", aws.StringValue(resp.Policy.PolicyUpdateToken))
if err = d.Set("resource_tags", flattenFMSResourceTags(resp.Policy.ResourceTags)); err != nil {
return err
}

securityServicePolicy := []map[string]string{{
"type": *resp.Policy.SecurityServicePolicyData.Type,
"managed_service_data": *resp.Policy.SecurityServicePolicyData.ManagedServiceData,
}}
if err = d.Set("security_service_policy_data", securityServicePolicy); err != nil {
return err
}

return nil
}

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

fmsPolicy := &fms.Policy{
PolicyName: aws.String(d.Get("name").(string)),
PolicyId: aws.String(d.Id()),
PolicyUpdateToken: aws.String(d.Get("policy_update_token").(string)),
RemediationEnabled: aws.Bool(d.Get("remediation_enabled").(bool)),
ResourceType: aws.String("ResourceTypeList"),
ResourceTypeList: expandStringList(d.Get("resource_type_list").(*schema.Set).List()),
ExcludeResourceTags: aws.Bool(d.Get("exclude_resource_tags").(bool)),
}

fmsPolicy.ExcludeMap = expandFMSPolicyMap(d.Get("exclude_map").([]interface{}))

fmsPolicy.IncludeMap = expandFMSPolicyMap(d.Get("include_map").([]interface{}))

fmsPolicy.ResourceTags = constructResourceTags(d.Get("resource_tags"))

securityServicePolicy := d.Get("security_service_policy_data").([]interface{})[0].(map[string]interface{})
fmsPolicy.SecurityServicePolicyData = &fms.SecurityServicePolicyData{
ManagedServiceData: aws.String(securityServicePolicy["managed_service_data"].(string)),
Type: aws.String(securityServicePolicy["type"].(string)),
}

params := &fms.PutPolicyInput{Policy: fmsPolicy}
_, err := conn.PutPolicy(params)

if err != nil {
return fmt.Errorf("Error modifying FMS Policy Rule: %s", err)
}

return resourceAwsFmsPolicyRead(d, meta)
}

func resourceAwsFmsPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).fmsconn
log.Printf("[DEBUG] Delete FMS Policy: %s", d.Id())

_, err := conn.DeletePolicy(&fms.DeletePolicyInput{
PolicyId: aws.String(d.Id()),
DeleteAllPolicyResources: aws.Bool(d.Get("delete_all_policy_resources").(bool)),
})

if isAWSErr(err, fms.ErrCodeResourceNotFoundException, "") {
return nil
}

if err != nil {
return fmt.Errorf("error deleting FMS Policy (%s): %s", d.Id(), err)
}

return nil
}

func expandFMSPolicyMap(set []interface{}) map[string][]*string {
fmsPolicyMap := map[string][]*string{}
if len(set) > 0 {
if _, ok := set[0].(map[string]interface{}); !ok {
return fmsPolicyMap
}
for key, listValue := range set[0].(map[string]interface{}) {
var flatKey string
switch key {
case "account":
flatKey = "ACCOUNT"
case "orgunit":
flatKey = "ORG_UNIT"
}

for _, value := range listValue.(*schema.Set).List() {
fmsPolicyMap[flatKey] = append(fmsPolicyMap[flatKey], aws.String(value.(string)))
}
}
}
return fmsPolicyMap
}

func flattenFMSPolicyMap(fmsPolicyMap map[string][]*string) []interface{} {
flatPolicyMap := map[string]interface{}{}

for key, value := range fmsPolicyMap {
switch key {
case "ACCOUNT":
flatPolicyMap["account"] = value
case "ORG_UNIT":
flatPolicyMap["orgunit"] = value
default:
log.Printf("[WARNING] Unexpected key (%q) found in FMS policy", key)
}
}

return []interface{}{flatPolicyMap}
}

func flattenFMSResourceTags(resourceTags []*fms.ResourceTag) map[string]interface{} {
resTags := map[string]interface{}{}

for _, v := range resourceTags {
resTags[*v.Key] = v.Value
}
return resTags
}

func constructResourceTags(rTags interface{}) []*fms.ResourceTag {
var rTagList []*fms.ResourceTag

tags := rTags.(map[string]interface{})
for k, v := range tags {
rTagList = append(rTagList, &fms.ResourceTag{Key: aws.String(k), Value: aws.String(v.(string))})
}

return rTagList
}
Loading

0 comments on commit bbefb8d

Please sign in to comment.