Skip to content

Commit bbefb8d

Browse files
authored
Merge pull request #9594 from robh007/fms-policy
r/aws_fms_policy: Add new resource for AWS Firewall Manager Policy
2 parents 3bd91cf + fe8440a commit bbefb8d

4 files changed

Lines changed: 762 additions & 0 deletions

File tree

aws/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ func Provider() *schema.Provider {
663663
"aws_fsx_lustre_file_system": resourceAwsFsxLustreFileSystem(),
664664
"aws_fsx_windows_file_system": resourceAwsFsxWindowsFileSystem(),
665665
"aws_fms_admin_account": resourceAwsFmsAdminAccount(),
666+
"aws_fms_policy": resourceAwsFmsPolicy(),
666667
"aws_gamelift_alias": resourceAwsGameliftAlias(),
667668
"aws_gamelift_build": resourceAwsGameliftBuild(),
668669
"aws_gamelift_fleet": resourceAwsGameliftFleet(),

aws/resource_aws_fms_policy.go

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
package aws
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/aws/aws-sdk-go/aws"
8+
"github.com/aws/aws-sdk-go/service/fms"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
11+
)
12+
13+
func resourceAwsFmsPolicy() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceAwsFmsPolicyCreate,
16+
Read: resourceAwsFmsPolicyRead,
17+
Update: resourceAwsFmsPolicyUpdate,
18+
Delete: resourceAwsFmsPolicyDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
23+
Schema: map[string]*schema.Schema{
24+
"name": {
25+
Type: schema.TypeString,
26+
Required: true,
27+
},
28+
29+
"delete_all_policy_resources": {
30+
Type: schema.TypeBool,
31+
Optional: true,
32+
Default: true,
33+
},
34+
35+
"exclude_resource_tags": {
36+
Type: schema.TypeBool,
37+
Required: true,
38+
},
39+
40+
"exclude_map": {
41+
Type: schema.TypeList,
42+
MaxItems: 1,
43+
Optional: true,
44+
DiffSuppressFunc: suppressMissingOptionalConfigurationBlock,
45+
Elem: &schema.Resource{
46+
Schema: map[string]*schema.Schema{
47+
"account": {
48+
Type: schema.TypeSet,
49+
Optional: true,
50+
Elem: &schema.Schema{
51+
Type: schema.TypeString,
52+
},
53+
},
54+
"orgunit": {
55+
Type: schema.TypeSet,
56+
Optional: true,
57+
Elem: &schema.Schema{
58+
Type: schema.TypeString,
59+
},
60+
},
61+
},
62+
},
63+
},
64+
65+
"include_map": {
66+
Type: schema.TypeList,
67+
MaxItems: 1,
68+
Optional: true,
69+
DiffSuppressFunc: suppressMissingOptionalConfigurationBlock,
70+
Elem: &schema.Resource{
71+
Schema: map[string]*schema.Schema{
72+
"account": {
73+
Type: schema.TypeSet,
74+
Optional: true,
75+
Elem: &schema.Schema{
76+
Type: schema.TypeString,
77+
},
78+
},
79+
"orgunit": {
80+
Type: schema.TypeSet,
81+
Optional: true,
82+
Elem: &schema.Schema{
83+
Type: schema.TypeString,
84+
},
85+
},
86+
},
87+
},
88+
},
89+
90+
"remediation_enabled": {
91+
Type: schema.TypeBool,
92+
Optional: true,
93+
},
94+
95+
"resource_type_list": {
96+
Type: schema.TypeSet,
97+
Required: true,
98+
Elem: &schema.Schema{
99+
Type: schema.TypeString,
100+
ValidateFunc: validation.StringInSlice([]string{"AWS::ApiGateway::Stage", "AWS::ElasticLoadBalancingV2::LoadBalancer", "AWS::CloudFront::Distribution"}, false),
101+
},
102+
Set: schema.HashString,
103+
},
104+
105+
"policy_update_token": {
106+
Type: schema.TypeString,
107+
Computed: true,
108+
},
109+
110+
"resource_tags": tagsSchema(),
111+
112+
"security_service_policy_data": {
113+
Type: schema.TypeList,
114+
Required: true,
115+
MaxItems: 1,
116+
Elem: &schema.Resource{
117+
Schema: map[string]*schema.Schema{
118+
"type": {
119+
Type: schema.TypeString,
120+
Required: true,
121+
},
122+
"managed_service_data": {
123+
Type: schema.TypeString,
124+
Optional: true,
125+
DiffSuppressFunc: suppressEquivalentJsonDiffs,
126+
},
127+
},
128+
},
129+
},
130+
"arn": {
131+
Type: schema.TypeString,
132+
Computed: true,
133+
},
134+
},
135+
}
136+
}
137+
138+
func resourceAwsFmsPolicyCreate(d *schema.ResourceData, meta interface{}) error {
139+
conn := meta.(*AWSClient).fmsconn
140+
141+
fmsPolicy := &fms.Policy{
142+
PolicyName: aws.String(d.Get("name").(string)),
143+
RemediationEnabled: aws.Bool(d.Get("remediation_enabled").(bool)),
144+
ResourceType: aws.String("ResourceTypeList"),
145+
ResourceTypeList: expandStringList(d.Get("resource_type_list").(*schema.Set).List()),
146+
ExcludeResourceTags: aws.Bool(d.Get("exclude_resource_tags").(bool)),
147+
}
148+
149+
securityServicePolicy := d.Get("security_service_policy_data").([]interface{})[0].(map[string]interface{})
150+
fmsPolicy.SecurityServicePolicyData = &fms.SecurityServicePolicyData{
151+
ManagedServiceData: aws.String(securityServicePolicy["managed_service_data"].(string)),
152+
Type: aws.String(securityServicePolicy["type"].(string)),
153+
}
154+
155+
if rTags, tagsOk := d.GetOk("resource_tags"); tagsOk {
156+
fmsPolicy.ResourceTags = constructResourceTags(rTags)
157+
}
158+
159+
if v, ok := d.GetOk("include_map"); ok {
160+
fmsPolicy.IncludeMap = expandFMSPolicyMap(v.([]interface{}))
161+
}
162+
163+
if v, ok := d.GetOk("exclude_map"); ok {
164+
fmsPolicy.ExcludeMap = expandFMSPolicyMap(v.([]interface{}))
165+
}
166+
167+
params := &fms.PutPolicyInput{
168+
Policy: fmsPolicy,
169+
}
170+
171+
var resp *fms.PutPolicyOutput
172+
var err error
173+
174+
resp, err = conn.PutPolicy(params)
175+
176+
if err != nil {
177+
return fmt.Errorf("Creating Policy Failed: %s", err.Error())
178+
}
179+
180+
d.SetId(aws.StringValue(resp.Policy.PolicyId))
181+
182+
return resourceAwsFmsPolicyRead(d, meta)
183+
}
184+
185+
func resourceAwsFmsPolicyRead(d *schema.ResourceData, meta interface{}) error {
186+
conn := meta.(*AWSClient).fmsconn
187+
188+
var resp *fms.GetPolicyOutput
189+
var req = &fms.GetPolicyInput{
190+
PolicyId: aws.String(d.Id()),
191+
}
192+
193+
resp, err := conn.GetPolicy(req)
194+
195+
if err != nil {
196+
if isAWSErr(err, fms.ErrCodeResourceNotFoundException, "") {
197+
log.Printf("[WARN] FMS Policy (%s) not found, removing from state", d.Id())
198+
d.SetId("")
199+
return nil
200+
}
201+
return err
202+
}
203+
204+
d.Set("arn", aws.StringValue(resp.PolicyArn))
205+
206+
d.Set("name", aws.StringValue(resp.Policy.PolicyName))
207+
d.Set("exclude_resource_tags", aws.BoolValue(resp.Policy.ExcludeResourceTags))
208+
if err = d.Set("exclude_map", flattenFMSPolicyMap(resp.Policy.ExcludeMap)); err != nil {
209+
return err
210+
}
211+
if err = d.Set("include_map", flattenFMSPolicyMap(resp.Policy.IncludeMap)); err != nil {
212+
return err
213+
}
214+
d.Set("remediation_enabled", aws.BoolValue(resp.Policy.RemediationEnabled))
215+
if err = d.Set("resource_type_list", resp.Policy.ResourceTypeList); err != nil {
216+
return err
217+
}
218+
d.Set("policy_update_token", aws.StringValue(resp.Policy.PolicyUpdateToken))
219+
if err = d.Set("resource_tags", flattenFMSResourceTags(resp.Policy.ResourceTags)); err != nil {
220+
return err
221+
}
222+
223+
securityServicePolicy := []map[string]string{{
224+
"type": *resp.Policy.SecurityServicePolicyData.Type,
225+
"managed_service_data": *resp.Policy.SecurityServicePolicyData.ManagedServiceData,
226+
}}
227+
if err = d.Set("security_service_policy_data", securityServicePolicy); err != nil {
228+
return err
229+
}
230+
231+
return nil
232+
}
233+
234+
func resourceAwsFmsPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
235+
conn := meta.(*AWSClient).fmsconn
236+
237+
fmsPolicy := &fms.Policy{
238+
PolicyName: aws.String(d.Get("name").(string)),
239+
PolicyId: aws.String(d.Id()),
240+
PolicyUpdateToken: aws.String(d.Get("policy_update_token").(string)),
241+
RemediationEnabled: aws.Bool(d.Get("remediation_enabled").(bool)),
242+
ResourceType: aws.String("ResourceTypeList"),
243+
ResourceTypeList: expandStringList(d.Get("resource_type_list").(*schema.Set).List()),
244+
ExcludeResourceTags: aws.Bool(d.Get("exclude_resource_tags").(bool)),
245+
}
246+
247+
fmsPolicy.ExcludeMap = expandFMSPolicyMap(d.Get("exclude_map").([]interface{}))
248+
249+
fmsPolicy.IncludeMap = expandFMSPolicyMap(d.Get("include_map").([]interface{}))
250+
251+
fmsPolicy.ResourceTags = constructResourceTags(d.Get("resource_tags"))
252+
253+
securityServicePolicy := d.Get("security_service_policy_data").([]interface{})[0].(map[string]interface{})
254+
fmsPolicy.SecurityServicePolicyData = &fms.SecurityServicePolicyData{
255+
ManagedServiceData: aws.String(securityServicePolicy["managed_service_data"].(string)),
256+
Type: aws.String(securityServicePolicy["type"].(string)),
257+
}
258+
259+
params := &fms.PutPolicyInput{Policy: fmsPolicy}
260+
_, err := conn.PutPolicy(params)
261+
262+
if err != nil {
263+
return fmt.Errorf("Error modifying FMS Policy Rule: %s", err)
264+
}
265+
266+
return resourceAwsFmsPolicyRead(d, meta)
267+
}
268+
269+
func resourceAwsFmsPolicyDelete(d *schema.ResourceData, meta interface{}) error {
270+
conn := meta.(*AWSClient).fmsconn
271+
log.Printf("[DEBUG] Delete FMS Policy: %s", d.Id())
272+
273+
_, err := conn.DeletePolicy(&fms.DeletePolicyInput{
274+
PolicyId: aws.String(d.Id()),
275+
DeleteAllPolicyResources: aws.Bool(d.Get("delete_all_policy_resources").(bool)),
276+
})
277+
278+
if isAWSErr(err, fms.ErrCodeResourceNotFoundException, "") {
279+
return nil
280+
}
281+
282+
if err != nil {
283+
return fmt.Errorf("error deleting FMS Policy (%s): %s", d.Id(), err)
284+
}
285+
286+
return nil
287+
}
288+
289+
func expandFMSPolicyMap(set []interface{}) map[string][]*string {
290+
fmsPolicyMap := map[string][]*string{}
291+
if len(set) > 0 {
292+
if _, ok := set[0].(map[string]interface{}); !ok {
293+
return fmsPolicyMap
294+
}
295+
for key, listValue := range set[0].(map[string]interface{}) {
296+
var flatKey string
297+
switch key {
298+
case "account":
299+
flatKey = "ACCOUNT"
300+
case "orgunit":
301+
flatKey = "ORG_UNIT"
302+
}
303+
304+
for _, value := range listValue.(*schema.Set).List() {
305+
fmsPolicyMap[flatKey] = append(fmsPolicyMap[flatKey], aws.String(value.(string)))
306+
}
307+
}
308+
}
309+
return fmsPolicyMap
310+
}
311+
312+
func flattenFMSPolicyMap(fmsPolicyMap map[string][]*string) []interface{} {
313+
flatPolicyMap := map[string]interface{}{}
314+
315+
for key, value := range fmsPolicyMap {
316+
switch key {
317+
case "ACCOUNT":
318+
flatPolicyMap["account"] = value
319+
case "ORG_UNIT":
320+
flatPolicyMap["orgunit"] = value
321+
default:
322+
log.Printf("[WARNING] Unexpected key (%q) found in FMS policy", key)
323+
}
324+
}
325+
326+
return []interface{}{flatPolicyMap}
327+
}
328+
329+
func flattenFMSResourceTags(resourceTags []*fms.ResourceTag) map[string]interface{} {
330+
resTags := map[string]interface{}{}
331+
332+
for _, v := range resourceTags {
333+
resTags[*v.Key] = v.Value
334+
}
335+
return resTags
336+
}
337+
338+
func constructResourceTags(rTags interface{}) []*fms.ResourceTag {
339+
var rTagList []*fms.ResourceTag
340+
341+
tags := rTags.(map[string]interface{})
342+
for k, v := range tags {
343+
rTagList = append(rTagList, &fms.ResourceTag{Key: aws.String(k), Value: aws.String(v.(string))})
344+
}
345+
346+
return rTagList
347+
}

0 commit comments

Comments
 (0)