From abb769f596fae9e2fe53dc1177a243a7168f5898 Mon Sep 17 00:00:00 2001 From: Igor Date: Thu, 29 Aug 2024 10:30:02 +0400 Subject: [PATCH] Added time units for ip_lists --- docs/resources/allowlist.md | 4 + docs/resources/denylist.md | 4 + docs/resources/graylist.md | 4 + docs/resources/trigger.md | 14 +++- examples/wallarm_allowlist.tf | 32 ++++++++ examples/wallarm_trigger.tf | 3 +- wallarm/resource_allowlist_test.go | 120 +++++++++++++++++++++++++++++ wallarm/resource_ip_list.go | 46 ++++++++++- wallarm/resource_trigger.go | 44 +++++++++-- 9 files changed, 262 insertions(+), 9 deletions(-) diff --git a/docs/resources/allowlist.md b/docs/resources/allowlist.md index 129cb5c..86a9943 100644 --- a/docs/resources/allowlist.md +++ b/docs/resources/allowlist.md @@ -41,6 +41,10 @@ resource "wallarm_allowlist" "allowlist_date" { * `time_format` - (**required**) block time format. Can be: - `Minutes` - Time in minutes (e.g. `60` is to block for 60 minutes) + - `Hours` - Time in hours (e.g. `5` is to block for 5 hours) + - `Days` - Time in days (e.g. `7` is to block for 7 days) + - `Weeks` - Time in weeks (e.g. `4` is to block for 4 weeks) + - `Months` - Time in weeks (e.g. `12` is to block for 12 months) - `RFC3339` - RFC3339 time (e.g. `2021-06-01T15:04:05+07:00`) * `time` - (**required**) time for (or until) which the IP address should be blocked. * `application` - (optional) list of application IDs. diff --git a/docs/resources/denylist.md b/docs/resources/denylist.md index 7d0bdb5..6799cac 100644 --- a/docs/resources/denylist.md +++ b/docs/resources/denylist.md @@ -41,6 +41,10 @@ resource "wallarm_denylist" "denylist_date" { * `time_format` - (**required**) block time format. Can be: - `Minutes` - Time in minutes (e.g. `60` is to block for 60 minutes) + - `Hours` - Time in hours (e.g. `5` is to block for 5 hours) + - `Days` - Time in days (e.g. `7` is to block for 7 days) + - `Weeks` - Time in weeks (e.g. `4` is to block for 4 weeks) + - `Months` - Time in weeks (e.g. `12` is to block for 12 months) - `RFC3339` - RFC3339 time (e.g. `2021-06-01T15:04:05+07:00`) * `time` - (**required**) time for (or until) which the IP address should be blocked. * `application` - (optional) list of application IDs. diff --git a/docs/resources/graylist.md b/docs/resources/graylist.md index 9749d2d..a8e2a59 100644 --- a/docs/resources/graylist.md +++ b/docs/resources/graylist.md @@ -41,6 +41,10 @@ resource "wallarm_graylist" "graylist_date" { * `time_format` - (**required**) block time format. Can be: - `Minutes` - Time in minutes (e.g. `60` is to block for 60 minutes) + - `Hours` - Time in hours (e.g. `5` is to block for 5 hours) + - `Days` - Time in days (e.g. `7` is to block for 7 days) + - `Weeks` - Time in weeks (e.g. `4` is to block for 4 weeks) + - `Months` - Time in weeks (e.g. `12` is to block for 12 months) - `RFC3339` - RFC3339 time (e.g. `2021-06-01T15:04:05+07:00`) * `time` - (**required**) time for (or until) which the IP address should be blocked. * `application` - (optional) list of application IDs. diff --git a/docs/resources/trigger.md b/docs/resources/trigger.md index 8937643..1a21b57 100644 --- a/docs/resources/trigger.md +++ b/docs/resources/trigger.md @@ -184,7 +184,10 @@ Example: ## Threshold `threshold` argument shares the available conditions which can be applied. It must **NOT** be specified when the `user_created` template is used. The conditions are: - - `period` - The period of time to count (in seconds). + - `period` - The period of time to count (in seconds by default). + - `time_format` - Time units for period. Can be: + * `Seconds` - By default, to measure in seconds. + * `Minutes` - To measure period in minutes. - `count` - The number of such events. - `operator` - (optional) The comparison operator. Valid values: * `gt` - Greater than @@ -213,8 +216,17 @@ Example: - `action_id` - (**required**) the type of action when triggered. * `send_notification` - send notification to existing integration resource. * `block_ips` - block the IP addresses from which the requests originated. + * `mark_as_brute` - to mark as bruteforce. + * `add_to_graylist` - to add to graylist. + * `group_attack_by_ip` - to group an attack by the same IP. - `integration_id` - the identificator of the existing integration. - `lock_time` - The time for which to block IP addresses in case of usage `block_ips`. + - `lock_time_format` - Time units to setup lock time. In seconds by default. Can be: + * `Minutes` - Time in minutes (e.g. `60` is to block for 60 minutes). + * `Hours` - Time in hours (e.g. `5` is to block for 5 hours). + * `Days` - Time in days (e.g. `7` is to block for 7 days). + * `Weeks` - Time in weeks (e.g. `4` is to block for 4 weeks). + * `Months` - Time in weeks (e.g. `12` is to block for 12 months). Example: diff --git a/examples/wallarm_allowlist.tf b/examples/wallarm_allowlist.tf index 6bb43a2..568f704 100644 --- a/examples/wallarm_allowlist.tf +++ b/examples/wallarm_allowlist.tf @@ -13,3 +13,35 @@ resource "wallarm_allowlist" "allowlist_date" { time_format = "RFC3339" time = "2026-01-02T15:04:05+07:00" } + +resource "wallarm_allowlist" "allowlist_date" { + ip_range = ["117.69.14.54/32"] + application = [1] + reason = "TEST ALLOWLIST" + time_format = "Hours" + time = 5 +} + +resource "wallarm_allowlist" "allowlist_date" { + ip_range = ["117.69.14.54/32"] + application = [1] + reason = "TEST ALLOWLIST" + time_format = "Days" + time = 3 +} + +resource "wallarm_allowlist" "allowlist_date" { + ip_range = ["117.69.14.54/32"] + application = [1] + reason = "TEST ALLOWLIST" + time_format = "Weeks" + time = 3 +} + +resource "wallarm_allowlist" "allowlist_date" { + ip_range = ["117.69.14.54/32"] + application = [1] + reason = "TEST ALLOWLIST" + time_format = "Months" + time = 3 +} diff --git a/examples/wallarm_trigger.tf b/examples/wallarm_trigger.tf index aa38ddf..5afa47a 100644 --- a/examples/wallarm_trigger.tf +++ b/examples/wallarm_trigger.tf @@ -81,7 +81,8 @@ resource "wallarm_trigger" "vector_trigger" { actions { action_id = "block_ips" - lock_time = 10000 + lock_time = 7 + lock_time_format = "Days" } } diff --git a/wallarm/resource_allowlist_test.go b/wallarm/resource_allowlist_test.go index a7d2018..3fb0ede 100644 --- a/wallarm/resource_allowlist_test.go +++ b/wallarm/resource_allowlist_test.go @@ -27,6 +27,82 @@ func TestAccWallarmAllowlistMinutes(t *testing.T) { }) } +func TestAccWallarmAllowlistHours(t *testing.T) { + rnd := generateRandomResourceName(10) + name := "wallarm_allowlist." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testWallarmAllowlistHours(rnd, "tf-test-"+rnd, "Hours", "5"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "reason", "tf-test-"+rnd), + resource.TestCheckResourceAttr(name, "time", "5"), + ), + }, + }, + }) +} + +func TestAccWallarmAllowlistDays(t *testing.T) { + rnd := generateRandomResourceName(10) + name := "wallarm_allowlist." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testWallarmAllowlistDays(rnd, "tf-test-"+rnd, "Days", "7"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "reason", "tf-test-"+rnd), + resource.TestCheckResourceAttr(name, "time", "7"), + ), + }, + }, + }) +} + +func TestAccWallarmAllowlistWeeks(t *testing.T) { + rnd := generateRandomResourceName(10) + name := "wallarm_allowlist." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testWallarmAllowlistWeeks(rnd, "tf-test-"+rnd, "Weeks", "4"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "reason", "tf-test-"+rnd), + resource.TestCheckResourceAttr(name, "time", "4"), + ), + }, + }, + }) +} + +func TestAccWallarmAllowlistMonths(t *testing.T) { + rnd := generateRandomResourceName(10) + name := "wallarm_allowlist." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testWallarmAllowlistMonths(rnd, "tf-test-"+rnd, "Months", "12"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "reason", "tf-test-"+rnd), + resource.TestCheckResourceAttr(name, "time", "12"), + ), + }, + }, + }) +} + func TestAccWallarmAllowlistRFC3339(t *testing.T) { rnd := generateRandomResourceName(10) name := "wallarm_allowlist." + rnd @@ -76,6 +152,50 @@ resource "wallarm_allowlist" "%[1]s" { }`, resourceID, reason, timeFormat, time) } +func testWallarmAllowlistHours(resourceID, reason, timeFormat, time string) string { + return fmt.Sprintf(` +resource "wallarm_allowlist" "%[1]s" { + ip_range = ["1.1.1.1/30", "2.2.2.2", "3.3.3.3/32"] + application = [1, 2] + reason = "%[2]s" + time_format = "%[3]s" + time = %[4]s # Hours +}`, resourceID, reason, timeFormat, time) +} + +func testWallarmAllowlistDays(resourceID, reason, timeFormat, time string) string { + return fmt.Sprintf(` +resource "wallarm_allowlist" "%[1]s" { + ip_range = ["1.1.1.1/30", "2.2.2.2", "3.3.3.3/32"] + application = [1, 2] + reason = "%[2]s" + time_format = "%[3]s" + time = %[4]s # Days +}`, resourceID, reason, timeFormat, time) +} + +func testWallarmAllowlistWeeks(resourceID, reason, timeFormat, time string) string { + return fmt.Sprintf(` +resource "wallarm_allowlist" "%[1]s" { + ip_range = ["1.1.1.1/30", "2.2.2.2", "3.3.3.3/32"] + application = [1, 2] + reason = "%[2]s" + time_format = "%[3]s" + time = %[4]s # Weeks +}`, resourceID, reason, timeFormat, time) +} + +func testWallarmAllowlistMonths(resourceID, reason, timeFormat, time string) string { + return fmt.Sprintf(` +resource "wallarm_allowlist" "%[1]s" { + ip_range = ["1.1.1.1/30", "2.2.2.2", "3.3.3.3/32"] + application = [1, 2] + reason = "%[2]s" + time_format = "%[3]s" + time = %[4]s # Months +}`, resourceID, reason, timeFormat, time) +} + func testWallarmAllowlistRFC3339(resourceID, reason, timeFormat, time string) string { return fmt.Sprintf(` resource "wallarm_allowlist" "%[1]s" { diff --git a/wallarm/resource_ip_list.go b/wallarm/resource_ip_list.go index c3a8b43..bae72ce 100644 --- a/wallarm/resource_ip_list.go +++ b/wallarm/resource_ip_list.go @@ -46,7 +46,7 @@ func resourceWallarmIPList(listType wallarm.IPListType) *schema.Resource { "time_format": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{"Minutes", "RFC3339"}, false), + ValidateFunc: validation.StringInSlice([]string{"Minutes", "RFC3339", "Hours", "Days", "Weeks", "Months"}, false), }, "time": { Type: schema.TypeString, @@ -136,6 +136,50 @@ func resourceWallarmIPListCreate(listType wallarm.IPListType) schema.CreateFunc currTime := time.Now() shiftTime := currTime.Add(time.Minute * time.Duration(expireTime)) unixTime = int(shiftTime.Unix()) + case "Hours": + expireTime, err := strconv.Atoi(d.Get("time").(string)) + if err != nil { + return fmt.Errorf("cannot parse time to integer. must be the number when `time_format` equals `Hours`, got %v", err) + } + if expireTime == 0 { + expireTime = 60045120 + } + currTime := time.Now() + shiftTime := currTime.Add(time.Hour * time.Duration(expireTime)) + unixTime = int(shiftTime.Unix()) + case "Days": + expireTime, err := strconv.Atoi(d.Get("time").(string)) + if err != nil { + return fmt.Errorf("cannot parse time to integer. must be the number when `time_format` equals `Days`, got %v", err) + } + if expireTime == 0 { + expireTime = 60045120 + } + currTime := time.Now() + shiftTime := currTime.Add(24 * time.Hour * time.Duration(expireTime)) + unixTime = int(shiftTime.Unix()) + case "Weeks": + expireTime, err := strconv.Atoi(d.Get("time").(string)) + if err != nil { + return fmt.Errorf("cannot parse time to integer. must be the number when `time_format` equals `Weeks`, got %v", err) + } + if expireTime == 0 { + expireTime = 60045120 + } + currTime := time.Now() + shiftTime := currTime.Add(7 * 24 * time.Hour * time.Duration(expireTime)) + unixTime = int(shiftTime.Unix()) + case "Months": + expireTime, err := strconv.Atoi(d.Get("time").(string)) + if err != nil { + return fmt.Errorf("cannot parse time to integer. must be the number when `time_format` equals `Months`, got %v", err) + } + if expireTime == 0 { + expireTime = 60045120 + } + currTime := time.Now() + shiftTime := currTime.AddDate(0, expireTime, 0) + unixTime = int(shiftTime.Unix()) case "RFC3339": expireTime, err := time.Parse(time.RFC3339, d.Get("time").(string)) if err != nil { diff --git a/wallarm/resource_trigger.go b/wallarm/resource_trigger.go index ddbd7c3..642cd6b 100644 --- a/wallarm/resource_trigger.go +++ b/wallarm/resource_trigger.go @@ -111,11 +111,12 @@ func resourceWallarmTrigger() *schema.Resource { "lock_time": { Type: schema.TypeInt, Optional: true, - // 5/15/30 minutes, 1/2/6/12 hours, 1/2/7/30 days, forever - ValidateFunc: validation.IntInSlice([]int{300, 900, 1800, - 3600, 7200, 21600, 43200, - 86400, 172800, 604800, 2592000, - 7776000}), + }, + "lock_time_format": { + Type: schema.TypeString, + Optional: true, + Default: "Seconds", + ValidateFunc: validation.StringInSlice([]string{"Seconds", "Minutes", "Hours", "Days", "Weeks", "Months"}, false), }, }, }, @@ -141,6 +142,12 @@ func resourceWallarmTrigger() *schema.Resource { Type: schema.TypeInt, Required: true, }, + "time_format": { + Type: schema.TypeString, + Optional: true, + Default: "Seconds", + ValidateFunc: validation.StringInSlice([]string{"Seconds", "Minutes"}, false), + }, }, }, }, @@ -453,7 +460,25 @@ func expandWallarmTriggerAction(d interface{}) (*[]wallarm.TriggerActions, error lockTime, ok := m["lock_time"] if ok { - a.Params.LockTime = lockTime.(int) + lockTimeInt := lockTime.(int) + switch m["lock_time_format"] { + case "Minutes": + lockTimeInt = lockTimeInt * 60 + case "Hours": + lockTimeInt = lockTimeInt * 60 * 60 + case "Days": + lockTimeInt = lockTimeInt * 60 * 60 * 24 + case "Weeks": + lockTimeInt = lockTimeInt * 60 * 60 * 24 * 7 + case "Months": + currTime := time.Now() + shiftTime := currTime.AddDate(0, lockTimeInt, 0) + lockTimeInt = int(shiftTime.Sub(currTime).Seconds()) + } + if lockTimeInt == 0 { + lockTimeInt = 7776000 // forever, our max time + } + a.Params.LockTime = lockTimeInt } actions = append(actions, a) @@ -476,6 +501,13 @@ func expandWallarmTriggerThreshold(d interface{}) (*wallarm.TriggerThreshold, er threshold.Period = periodInt } + timeFormat, ok := m["time_format"] + if ok { + if timeFormat == "Minutes" { + threshold.Period = 60 * threshold.Period + } + } + operator, ok := m["operator"] if ok { threshold.Operator = operator.(string)