diff --git a/client/firewall_config.go b/client/firewall_config.go
index 4fa03916..51f3855a 100644
--- a/client/firewall_config.go
+++ b/client/firewall_config.go
@@ -16,7 +16,8 @@ type FirewallConfig struct {
CRS map[string]CoreRuleSet `json:"crs,omitempty"`
}
type ManagedRule struct {
- Active bool `json:"active"`
+ Active bool `json:"active"`
+ Action string `json:"action,omitempty"`
}
type FirewallRule struct {
diff --git a/docs/resources/firewall_config.md b/docs/resources/firewall_config.md
index 0891e48c..ba7f8b5d 100644
--- a/docs/resources/firewall_config.md
+++ b/docs/resources/firewall_config.md
@@ -157,6 +157,11 @@ resource "vercel_firewall_config" "managed" {
rfi = { action = "deny" }
gen = { action = "deny" }
}
+
+ bot_filter {
+ action = "log"
+ active = true
+ }
}
}
@@ -230,8 +235,18 @@ Read-Only:
Optional:
+- `bot_filter` (Block, Optional) Enable the bot_filter managed ruleset and select action (see [below for nested schema](#nestedblock--managed_rulesets--bot_filter))
- `owasp` (Block, Optional) Enable the owasp managed rulesets and select ruleset behaviors (see [below for nested schema](#nestedblock--managed_rulesets--owasp))
+
+### Nested Schema for `managed_rulesets.bot_filter`
+
+Optional:
+
+- `action` (String)
+- `active` (Boolean)
+
+
### Nested Schema for `managed_rulesets.owasp`
@@ -404,7 +419,7 @@ Required:
Optional:
-- `action_duration` (String) Forward persistence of a rule aciton
+- `action_duration` (String) Forward persistence of a rule action
- `rate_limit` (Attributes) Behavior or a rate limiting action. Required if action is rate_limit (see [below for nested schema](#nestedatt--rules--rule--action--rate_limit))
- `redirect` (Attributes) How to redirect a request. Required if action is redirect (see [below for nested schema](#nestedatt--rules--rule--action--redirect))
diff --git a/examples/resources/vercel_firewall_config/resource.tf b/examples/resources/vercel_firewall_config/resource.tf
index 4fff6455..4b2099eb 100644
--- a/examples/resources/vercel_firewall_config/resource.tf
+++ b/examples/resources/vercel_firewall_config/resource.tf
@@ -142,6 +142,11 @@ resource "vercel_firewall_config" "managed" {
rfi = { action = "deny" }
gen = { action = "deny" }
}
+
+ bot_filter {
+ action = "log"
+ active = true
+ }
}
}
diff --git a/vercel/resource_firewall_config.go b/vercel/resource_firewall_config.go
index f2d44c84..7a3bcb4a 100644
--- a/vercel/resource_firewall_config.go
+++ b/vercel/resource_firewall_config.go
@@ -170,6 +170,17 @@ Define Custom Rules to shape the way your traffic is handled by the Vercel Edge
},
},
},
+ "bot_filter": schema.SingleNestedBlock{
+ Description: "Enable the bot_filter managed ruleset and select action",
+ Attributes: map[string]schema.Attribute{
+ "active": schema.BoolAttribute{
+ Optional: true,
+ },
+ "action": schema.StringAttribute{
+ Optional: true,
+ },
+ },
+ },
},
},
"rules": schema.SingleNestedBlock{
@@ -255,7 +266,7 @@ Define Custom Rules to shape the way your traffic is handled by the Vercel Edge
},
},
"action_duration": schema.StringAttribute{
- Description: "Forward persistence of a rule aciton",
+ Description: "Forward persistence of a rule action",
Optional: true,
},
},
@@ -443,7 +454,8 @@ type FirewallConfig struct {
}
type FirewallManagedRulesets struct {
- OWASP *CRSRule `tfsdk:"owasp"`
+ OWASP *CRSRule `tfsdk:"owasp"`
+ BotFilter *BotFilterConfig `tfsdk:"bot_filter"`
}
type CRSRule struct {
@@ -479,6 +491,11 @@ type CRSRuleConfig struct {
Action types.String `tfsdk:"action"`
}
+type BotFilterConfig struct {
+ Active types.Bool `tfsdk:"active"`
+ Action types.String `tfsdk:"action"`
+}
+
type FirewallRules struct {
Rules []FirewallRule `tfsdk:"rule"`
}
@@ -756,7 +773,7 @@ func fromCRS(conf map[string]client.CoreRuleSet, refMr *FirewallManagedRulesets)
if refMr != nil && refMr.OWASP != nil {
ref = refMr.OWASP
}
- if conf == nil || ref == nil {
+ if conf == nil || ref == nil || refMr.OWASP == nil {
return nil
}
return &CRSRule{
@@ -838,10 +855,20 @@ func fromClient(conf client.FirewallConfig, state FirewallConfig) (FirewallConfi
cfg.IPRules = &IPRules{Rules: ipRules}
}
- managedRulesets := &FirewallManagedRulesets{}
- if conf.ManagedRulesets != nil && conf.CRS != nil {
+ if len(conf.ManagedRulesets) > 0 {
+ managedRulesets := &FirewallManagedRulesets{}
cfg.ManagedRulesets = managedRulesets
- cfg.ManagedRulesets.OWASP = fromCRS(conf.CRS, state.ManagedRulesets)
+ if conf.CRS != nil && state.ManagedRulesets != nil {
+ cfg.ManagedRulesets.OWASP = fromCRS(conf.CRS, state.ManagedRulesets)
+ }
+ botFilter, botFilterExist := conf.ManagedRulesets["bot_filter"]
+ if botFilterExist {
+ botFilterConf := &BotFilterConfig{
+ Active: types.BoolValue(botFilter.Active),
+ Action: types.StringValue(botFilter.Action),
+ }
+ cfg.ManagedRulesets.BotFilter = botFilterConf
+ }
}
return cfg, nil
@@ -870,6 +897,13 @@ func (f *FirewallConfig) toClient() (client.FirewallConfig, error) {
}
}
}
+ botFilter := f.ManagedRulesets.BotFilter
+ if botFilter != nil {
+ conf.ManagedRulesets["bot_filter"] = client.ManagedRule{
+ Active: botFilter.Active.ValueBool(),
+ Action: botFilter.Action.ValueString(),
+ }
+ }
}
if f.Rules != nil && len(f.Rules.Rules) > 0 {
for _, rule := range f.Rules.Rules {
diff --git a/vercel/resource_firewall_config_test.go b/vercel/resource_firewall_config_test.go
index 07e10ba7..3a84b19b 100644
--- a/vercel/resource_firewall_config_test.go
+++ b/vercel/resource_firewall_config_test.go
@@ -169,6 +169,15 @@ func TestAcc_FirewallConfigResource(t *testing.T) {
"vercel_firewall_config.ips",
"ip_rules.rule.2.hostname",
"*"),
+
+ resource.TestCheckResourceAttr(
+ "vercel_firewall_config.botfilter",
+ "managed_rulesets.bot_filter.action",
+ "challenge"),
+ resource.TestCheckResourceAttr(
+ "vercel_firewall_config.botfilter",
+ "managed_rulesets.bot_filter.active",
+ "true"),
),
},
{
@@ -186,6 +195,11 @@ func TestAcc_FirewallConfigResource(t *testing.T) {
ResourceName: "vercel_firewall_config.ips",
ImportStateIdFunc: getFirewallImportID("vercel_firewall_config.ips"),
},
+ {
+ ImportState: true,
+ ResourceName: "vercel_firewall_config.botfilter",
+ ImportStateIdFunc: getFirewallImportID("vercel_firewall_config.botfilter"),
+ },
{
Config: testAccFirewallConfigResourceUpdated(name, teamIDConfig(t)),
Check: resource.ComposeAggregateTestCheckFunc(
@@ -329,6 +343,15 @@ func TestAcc_FirewallConfigResource(t *testing.T) {
"vercel_firewall_config.ips",
"ip_rules.rule.2.hostname",
"*"),
+
+ resource.TestCheckResourceAttr(
+ "vercel_firewall_config.botfilter",
+ "managed_rulesets.bot_filter.action",
+ "deny"),
+ resource.TestCheckResourceAttr(
+ "vercel_firewall_config.botfilter",
+ "managed_rulesets.bot_filter.active",
+ "false"),
),
},
},
@@ -485,6 +508,23 @@ resource "vercel_firewall_config" "ips" {
}
}
+resource "vercel_project" "botfilter" {
+ name = "test-acc-%[1]s-botfilter"
+ %[2]s
+}
+
+resource "vercel_firewall_config" "botfilter" {
+ project_id = vercel_project.botfilter.id
+ %[2]s
+
+ managed_rulesets {
+ bot_filter {
+ action = "challenge"
+ active = true
+ }
+ }
+}
+
`, name, teamID)
}
@@ -655,5 +695,22 @@ resource "vercel_firewall_config" "neg" {
}
}
}
+
+resource "vercel_project" "botfilter" {
+ name = "test-acc-%[1]s-botfilter"
+ %[2]s
+}
+
+resource "vercel_firewall_config" "botfilter" {
+ project_id = vercel_project.botfilter.id
+ %[2]s
+
+ managed_rulesets {
+ bot_filter {
+ action = "deny"
+ active = false
+ }
+ }
+}
`, name, teamID)
}