-
Notifications
You must be signed in to change notification settings - Fork 643
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2672 from cwlowder/cwlowder/add-bot-management-re…
…source
- Loading branch information
Showing
8 changed files
with
412 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:new-resource | ||
introduce bot management resource | ||
``` |
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,63 @@ | ||
--- | ||
page_title: "cloudflare_bot_management Resource - Cloudflare" | ||
subcategory: "" | ||
description: |- | ||
Provides a resource to configure Bot Management. | ||
Specifically, this resource can be used to manage: | ||
Bot Fight ModeSuper Bot Fight ModeBot Management for Enterprise | ||
--- | ||
|
||
# cloudflare_bot_management (Resource) | ||
|
||
Provides a resource to configure Bot Management. | ||
|
||
Specifically, this resource can be used to manage: | ||
|
||
- **Bot Fight Mode** | ||
- **Super Bot Fight Mode** | ||
- **Bot Management for Enterprise** | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "cloudflare_bot_management" "example" { | ||
zone_id = "0da42c8d2132a9ddaf714f9e7c920711" | ||
enable_js = true | ||
sbfm_definitely_automated = "block" | ||
sbfm_likely_automated = "managed_challenge" | ||
sbfm_verified_bots = "allow" | ||
sbfm_static_resource_protection = false | ||
optimize_wordpress = true | ||
} | ||
``` | ||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `zone_id` (String) The zone identifier to target for the resource. **Modifying this attribute will force creation of a new resource.** | ||
|
||
### Optional | ||
|
||
- `auto_update_model` (Boolean) Automatically update to the newest bot detection models created by Cloudflare as they are released. [Learn more.](https://developers.cloudflare.com/bots/reference/machine-learning-models#model-versions-and-release-notes). | ||
- `enable_js` (Boolean) Use lightweight, invisible JavaScript detections to improve Bot Management. [Learn more about JavaScript Detections](https://developers.cloudflare.com/bots/reference/javascript-detections/). | ||
- `fight_mode` (Boolean) Whether to enable Bot Fight Mode. | ||
- `optimize_wordpress` (Boolean) Whether to optimize Super Bot Fight Mode protections for Wordpress. | ||
- `sbfm_definitely_automated` (String) Super Bot Fight Mode (SBFM) action to take on definitely automated requests. | ||
- `sbfm_likely_automated` (String) Super Bot Fight Mode (SBFM) action to take on likely automated requests. | ||
- `sbfm_static_resource_protection` (Boolean) Super Bot Fight Mode (SBFM) to enable static resource protection. Enable if static resources on your application need bot protection. Note: Static resource protection can also result in legitimate traffic being blocked. | ||
- `sbfm_verified_bots` (String) Super Bot Fight Mode (SBFM) action to take on verified bots requests. | ||
- `suppress_session_score` (Boolean) Whether to disable tracking the highest bot score for a session in the Bot Management cookie. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. | ||
- `using_latest_model` (Boolean) A read-only field that indicates whether the zone currently is running the latest ML model. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
$ terraform import cloudflare_bot_management.example <zone_id> | ||
``` |
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 @@ | ||
$ terraform import cloudflare_bot_management.example <zone_id> |
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,9 @@ | ||
resource "cloudflare_bot_management" "example" { | ||
zone_id = "0da42c8d2132a9ddaf714f9e7c920711" | ||
enable_js = true | ||
sbfm_definitely_automated = "block" | ||
sbfm_likely_automated = "managed_challenge" | ||
sbfm_verified_bots = "allow" | ||
sbfm_static_resource_protection = false | ||
optimize_wordpress = true | ||
} |
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
155 changes: 155 additions & 0 deletions
155
internal/sdkv2provider/resource_cloudflare_bot_management.go
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,155 @@ | ||
package sdkv2provider | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/MakeNowJust/heredoc/v2" | ||
"github.com/cloudflare/cloudflare-go" | ||
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func resourceCloudflareBotManagement() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: resourceCloudflareBotManagementSchema(), | ||
CreateContext: resourceCloudflareBotManagementCreate, | ||
ReadContext: resourceCloudflareBotManagementRead, | ||
UpdateContext: resourceCloudflareBotManagementUpdate, | ||
DeleteContext: resourceCloudflareBotManagementDelete, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: resourceCloudflareBotManagementImport, | ||
}, | ||
Description: heredoc.Doc(`Provides a resource to configure Bot Management. | ||
Specifically, this resource can be used to manage: | ||
- **Bot Fight Mode** | ||
- **Super Bot Fight Mode** | ||
- **Bot Management for Enterprise** | ||
`), | ||
} | ||
} | ||
|
||
func resourceCloudflareBotManagementCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
d.SetId(d.Get(consts.ZoneIDSchemaKey).(string)) | ||
|
||
return resourceCloudflareBotManagementUpdate(ctx, d, meta) | ||
} | ||
|
||
func resourceCloudflareBotManagementRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*cloudflare.API) | ||
bm, err := client.GetBotManagement(ctx, cloudflare.ZoneIdentifier(d.Id())) | ||
if err != nil { | ||
return diag.FromErr(fmt.Errorf("failed to fetch bot management configuration: %w", err)) | ||
} | ||
|
||
if bm.EnableJS != nil { | ||
d.Set("enable_js", bm.EnableJS) | ||
} | ||
|
||
if bm.FightMode != nil { | ||
d.Set("fight_mode", bm.FightMode) | ||
} | ||
|
||
if bm.SBFMDefinitelyAutomated != nil { | ||
d.Set("sbfm_definitely_automated", bm.SBFMDefinitelyAutomated) | ||
} | ||
|
||
if bm.SBFMLikelyAutomated != nil { | ||
d.Set("sbfm_likely_automated", bm.SBFMLikelyAutomated) | ||
} | ||
|
||
if bm.SBFMVerifiedBots != nil { | ||
d.Set("sbfm_verified_bots", bm.SBFMVerifiedBots) | ||
} | ||
|
||
if bm.SBFMStaticResourceProtection != nil { | ||
d.Set("sbfm_static_resource_protection", bm.SBFMStaticResourceProtection) | ||
} | ||
|
||
if bm.OptimizeWordpress != nil { | ||
d.Set("optimize_wordpress", bm.OptimizeWordpress) | ||
} | ||
|
||
if bm.SuppressSessionScore != nil { | ||
d.Set("suppress_session_score", bm.SuppressSessionScore) | ||
} | ||
|
||
if bm.AutoUpdateModel != nil { | ||
d.Set("auto_update_model", bm.AutoUpdateModel) | ||
} | ||
|
||
if bm.UsingLatestModel != nil { | ||
d.Set("using_latest_model", bm.UsingLatestModel) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceCloudflareBotManagementUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*cloudflare.API) | ||
zoneID := d.Get(consts.ZoneIDSchemaKey).(string) | ||
|
||
params := buildBotManagementParams(d) | ||
|
||
_, err := client.UpdateBotManagement(ctx, cloudflare.ZoneIdentifier(zoneID), params) | ||
if err != nil { | ||
return diag.FromErr(errors.Wrap(err, "failed to update bot management configuration")) | ||
} | ||
|
||
return resourceCloudflareBotManagementRead(ctx, d, meta) | ||
} | ||
|
||
// Deletion of bot management configuration is not something we support, we will | ||
// use a dummy handler for now. | ||
func resourceCloudflareBotManagementDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
return nil | ||
} | ||
|
||
func resourceCloudflareBotManagementImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { | ||
d.SetId(d.Id()) | ||
d.Set(consts.ZoneIDSchemaKey, d.Id()) | ||
|
||
resourceCloudflareBotManagementRead(ctx, d, meta) | ||
|
||
return []*schema.ResourceData{d}, nil | ||
} | ||
|
||
func buildBotManagementParams(d *schema.ResourceData) cloudflare.UpdateBotManagementParams { | ||
bm := cloudflare.UpdateBotManagementParams{} | ||
|
||
if val, exists := d.GetOkExists("enable_js"); exists { | ||
bm.EnableJS = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
if val, exists := d.GetOkExists("fight_mode"); exists { | ||
bm.EnableJS = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
|
||
if val, exists := d.GetOkExists("sbfm_definitely_automated"); exists { | ||
bm.SBFMDefinitelyAutomated = cloudflare.StringPtr(val.(string)) | ||
} | ||
if val, exists := d.GetOkExists("sbfm_likely_automated"); exists { | ||
bm.SBFMLikelyAutomated = cloudflare.StringPtr(val.(string)) | ||
} | ||
if val, exists := d.GetOkExists("sbfm_verified_bots"); exists { | ||
bm.SBFMVerifiedBots = cloudflare.StringPtr(val.(string)) | ||
} | ||
if val, exists := d.GetOkExists("sbfm_static_resource_protection"); exists { | ||
bm.SBFMStaticResourceProtection = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
if val, exists := d.GetOkExists("optimize_wordpress"); exists { | ||
bm.OptimizeWordpress = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
|
||
if val, exists := d.GetOkExists("suppress_session_score"); exists { | ||
bm.SuppressSessionScore = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
if val, exists := d.GetOkExists("auto_update_model"); exists { | ||
bm.AutoUpdateModel = cloudflare.BoolPtr(val.(bool)) | ||
} | ||
|
||
return bm | ||
} |
113 changes: 113 additions & 0 deletions
113
internal/sdkv2provider/resource_cloudflare_bot_management_test.go
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,113 @@ | ||
package sdkv2provider | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/cloudflare/cloudflare-go" | ||
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts" | ||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
) | ||
|
||
func TestAccCloudflareBotManagement_SBFM(t *testing.T) { | ||
rnd := generateRandomResourceName() | ||
resourceID := "cloudflare_bot_management." + rnd | ||
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") | ||
|
||
sbfmConfig := cloudflare.BotManagement{ | ||
EnableJS: cloudflare.BoolPtr(true), | ||
SBFMDefinitelyAutomated: cloudflare.StringPtr("managed_challenge"), | ||
SBFMLikelyAutomated: cloudflare.StringPtr("block"), | ||
SBFMVerifiedBots: cloudflare.StringPtr("allow"), | ||
SBFMStaticResourceProtection: cloudflare.BoolPtr(false), | ||
OptimizeWordpress: cloudflare.BoolPtr(true), | ||
} | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProviderFactories: providerFactories, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testCloudflareBotManagementSBFM(rnd, zoneID, sbfmConfig), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), | ||
resource.TestCheckResourceAttr(resourceID, "enable_js", "true"), | ||
resource.TestCheckResourceAttr(resourceID, "sbfm_definitely_automated", "managed_challenge"), | ||
resource.TestCheckResourceAttr(resourceID, "sbfm_likely_automated", "block"), | ||
resource.TestCheckResourceAttr(resourceID, "sbfm_verified_bots", "allow"), | ||
resource.TestCheckResourceAttr(resourceID, "sbfm_static_resource_protection", "false"), | ||
resource.TestCheckResourceAttr(resourceID, "optimize_wordpress", "true"), | ||
), | ||
}, | ||
{ | ||
ResourceName: resourceID, | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccCloudflareBotManagement_Unentitled(t *testing.T) { | ||
rnd := generateRandomResourceName() | ||
resourceID := "cloudflare_bot_management." + rnd | ||
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") | ||
|
||
bmEntConfig := cloudflare.BotManagement{ | ||
EnableJS: cloudflare.BoolPtr(true), | ||
SuppressSessionScore: cloudflare.BoolPtr(false), | ||
AutoUpdateModel: cloudflare.BoolPtr(false), | ||
} | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProviderFactories: providerFactories, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testCloudflareBotManagementEntSubscription(rnd, zoneID, bmEntConfig), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), | ||
resource.TestCheckResourceAttr(resourceID, "enable_js", "true"), | ||
resource.TestCheckResourceAttr(resourceID, "suppress_session_score", "false"), | ||
resource.TestCheckResourceAttr(resourceID, "auto_update_model", "false"), | ||
), | ||
ExpectError: regexp.MustCompile("zone not entitled to disable"), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testCloudflareBotManagementSBFM(resourceName, rnd string, bm cloudflare.BotManagement) string { | ||
return fmt.Sprintf(` | ||
resource "cloudflare_bot_management" "%[1]s" { | ||
zone_id = "%[2]s" | ||
enable_js = "%[3]t" | ||
sbfm_definitely_automated = "%[4]s" | ||
sbfm_likely_automated = "%[5]s" | ||
sbfm_verified_bots = "%[6]s" | ||
sbfm_static_resource_protection = "%[7]t" | ||
optimize_wordpress = "%[8]t" | ||
} | ||
`, resourceName, rnd, | ||
*bm.EnableJS, *bm.SBFMDefinitelyAutomated, | ||
*bm.SBFMLikelyAutomated, *bm.SBFMVerifiedBots, | ||
*bm.SBFMStaticResourceProtection, *bm.OptimizeWordpress) | ||
} | ||
|
||
func testCloudflareBotManagementEntSubscription(resourceName, rnd string, bm cloudflare.BotManagement) string { | ||
return fmt.Sprintf(` | ||
resource "cloudflare_bot_management" "%[1]s" { | ||
zone_id = "%[2]s" | ||
enable_js = "%[3]t" | ||
suppress_session_score = "%[4]t" | ||
auto_update_model = "%[5]t" | ||
} | ||
`, resourceName, rnd, | ||
*bm.EnableJS, *bm.SuppressSessionScore, *bm.AutoUpdateModel) | ||
} |
Oops, something went wrong.