-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding WAF Rule Exclusions to WAF Configuration resource (#328)
* Adding WAF Exclusions to WAF Configuration resource During this implementation, I've refactored some of the WAF acceptance tests to reduce overlapping: 1. TestAccFastlyServiceWAFVersionV1ImportWithRules was merged into TestAccFastlyServiceWAFVersionV1Import. This tests was also enhanced to include WAF exclusions 1. TestAccFastlyServiceWAFVersionV1AddWithRules and TestAccFastlyServiceWAFVersionV1DeleteRules was merged into TestAccFastlyServiceWAFVersionV1UpdateRules. The update tests was performing add, update and delete already. TestAccFastlyServiceWAFVersionV1UpdateRules was renamed to TestAccFastlyServiceWAFVersionV1AddUpdateDeleteRules to make it clearer Co-authored-by: Zsolt Balvanyos <[email protected]> * Changing WAF Exclusion terminology to WAF Rule Exclusion * Changing go imports to group them by stdlib and external. Pointing go-fastly to v2.0.0-alpha.2. Changing provider to use new struct format (include is now a slice instead of a string). Cleaned up go.sum Co-authored-by: Zsolt Balvanyos <[email protected]>
- Loading branch information
1 parent
9092a7d
commit c336db2
Showing
13 changed files
with
1,158 additions
and
149 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,213 @@ | ||
package fastly | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strconv" | ||
|
||
gofastly "github.com/fastly/go-fastly/v2/fastly" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/validation" | ||
) | ||
|
||
var wafRuleExclusion = &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Name of the exclusion.", | ||
}, | ||
"condition": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "A conditional expression in VCL used to determine if the condition is met.", | ||
}, | ||
"exclusion_type": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "The type of exclusion.", | ||
ValidateFunc: validateExecutionType(), | ||
}, | ||
"modsec_rule_ids": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Description: "The modsec rule IDs to exclude.", | ||
Elem: &schema.Schema{Type: schema.TypeInt}, | ||
}, | ||
"number": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
Description: "A sequential ID assigned to the exclusion.", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
func readWAFRuleExclusions(meta interface{}, d *schema.ResourceData, wafVersionNumber int) error { | ||
conn := meta.(*FastlyClient).conn | ||
wafID := d.Get("waf_id").(string) | ||
|
||
resp, e := conn.ListAllWAFRuleExclusions(&gofastly.ListAllWAFRuleExclusionsInput{ | ||
WAFID: wafID, | ||
WAFVersionNumber: wafVersionNumber, | ||
Include: []string{"waf_rules"}, | ||
}) | ||
|
||
if e != nil { | ||
return e | ||
} | ||
|
||
err := d.Set("rule_exclusion", flattenWAFRuleExclusions(resp.Items)) | ||
|
||
if err != nil { | ||
log.Printf("[WARN] Error setting WAF rule exclusions for (%s): %s", d.Id(), err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func flattenWAFRuleExclusions(exclusions []*gofastly.WAFRuleExclusion) []map[string]interface{} { | ||
var result []map[string]interface{} | ||
|
||
for _, exclusion := range exclusions { | ||
|
||
m := make(map[string]interface{}) | ||
if exclusion.Name != nil { | ||
m["name"] = *exclusion.Name | ||
} | ||
if exclusion.Number != nil { | ||
m["number"] = *exclusion.Number | ||
} | ||
if exclusion.Condition != nil { | ||
m["condition"] = *exclusion.Condition | ||
} | ||
if exclusion.ExclusionType != nil { | ||
m["exclusion_type"] = *exclusion.ExclusionType | ||
} | ||
|
||
var rules []interface{} | ||
for _, rule := range exclusion.Rules { | ||
rules = append(rules, rule.ModSecID) | ||
} | ||
if len(rules) > 0 { | ||
m["modsec_rule_ids"] = schema.NewSet(schema.HashInt, rules) | ||
} | ||
result = append(result, m) | ||
} | ||
|
||
return result | ||
} | ||
|
||
func updateWAFRuleExclusions(d *schema.ResourceData, meta interface{}, wafID string, wafVersionNumber int) error { | ||
|
||
os, ns := d.GetChange("rule_exclusion") | ||
|
||
if os == nil { | ||
os = new(schema.Set) | ||
} | ||
if ns == nil { | ||
ns = new(schema.Set) | ||
} | ||
|
||
oss := os.(*schema.Set) | ||
nss := ns.(*schema.Set) | ||
|
||
add := nss.Difference(oss).List() | ||
remove := oss.Difference(nss).List() | ||
|
||
var err error | ||
|
||
err = deleteWAFRuleExclusion(remove, meta, wafID, wafVersionNumber) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = createWAFRuleExclusion(add, meta, wafID, wafVersionNumber) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func deleteWAFRuleExclusion(remove []interface{}, meta interface{}, wafID string, wafVersionNumber int) error { | ||
conn := meta.(*FastlyClient).conn | ||
|
||
for _, aRaw := range remove { | ||
a := aRaw.(map[string]interface{}) | ||
|
||
err := conn.DeleteWAFRuleExclusion(&gofastly.DeleteWAFRuleExclusionInput{ | ||
Number: a["number"].(int), | ||
WAFID: wafID, | ||
WAFVersionNumber: wafVersionNumber, | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func createWAFRuleExclusion(add []interface{}, meta interface{}, wafID string, wafVersionNumber int) error { | ||
conn := meta.(*FastlyClient).conn | ||
|
||
for _, aRaw := range add { | ||
a := aRaw.(map[string]interface{}) | ||
|
||
var rules []*gofastly.WAFRule | ||
if a["exclusion_type"] == gofastly.WAFRuleExclusionTypeRule { | ||
for _, ruleId := range a["modsec_rule_ids"].(*schema.Set).List() { | ||
rules = append(rules, &gofastly.WAFRule{ | ||
ID: strconv.Itoa(ruleId.(int)), | ||
}) | ||
} | ||
} else { | ||
rules = nil | ||
} | ||
|
||
_, err := conn.CreateWAFRuleExclusion(&gofastly.CreateWAFRuleExclusionInput{ | ||
WAFID: wafID, | ||
WAFVersionNumber: wafVersionNumber, | ||
WAFRuleExclusion: &gofastly.WAFRuleExclusion{ | ||
Name: strToPtr(a["name"].(string)), | ||
ExclusionType: strToPtr(a["exclusion_type"].(string)), | ||
Condition: strToPtr(a["condition"].(string)), | ||
Rules: rules, | ||
}, | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func validateExecutionType() schema.SchemaValidateFunc { | ||
return validation.StringInSlice( | ||
[]string{ | ||
gofastly.WAFRuleExclusionTypeRule, | ||
gofastly.WAFRuleExclusionTypeWAF, | ||
}, | ||
false, | ||
) | ||
} | ||
|
||
func validateWAFRuleExclusion(d *schema.ResourceDiff) error { | ||
for _, i := range d.Get("rule_exclusion").(*schema.Set).List() { | ||
wafRuleExclusion := i.(map[string]interface{}) | ||
|
||
if wafRuleExclusion["exclusion_type"] == gofastly.WAFRuleExclusionTypeWAF && len(wafRuleExclusion["modsec_rule_ids"].(*schema.Set).List()) > 0 { | ||
return fmt.Errorf("must not set \"modsec_rule_ids\" with \"waf\" exclusion type in exclusion \"%s\"", wafRuleExclusion["name"]) | ||
} | ||
if wafRuleExclusion["exclusion_type"] == gofastly.WAFRuleExclusionTypeRule && len(wafRuleExclusion["modsec_rule_ids"].(*schema.Set).List()) == 0 { | ||
return fmt.Errorf("must set \"modsec_rule_ids\" with \"rule\" exclusion type in exclusion \"%s\"", wafRuleExclusion["name"]) | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.