From df5a1cc3bbfeee813bc4851266c051df8c72fe5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Alberto=20Polo?= Date: Wed, 30 Mar 2022 12:22:26 +0200 Subject: [PATCH 1/3] Add logging configuration for rulesets rules --- .changelog/1538.txt | 3 + cloudflare/resource_cloudflare_ruleset.go | 25 +++++++ .../resource_cloudflare_ruleset_test.go | 66 +++++++++++++++++++ cloudflare/schema_cloudflare_ruleset.go | 13 ++++ website/docs/r/ruleset.html.markdown | 12 ++-- 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 .changelog/1538.txt diff --git a/.changelog/1538.txt b/.changelog/1538.txt new file mode 100644 index 0000000000..bb78a1eb48 --- /dev/null +++ b/.changelog/1538.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_ruleset: add support for rule `logging` +``` diff --git a/cloudflare/resource_cloudflare_ruleset.go b/cloudflare/resource_cloudflare_ruleset.go index 3666ede3a0..7a1ba4b3b0 100644 --- a/cloudflare/resource_cloudflare_ruleset.go +++ b/cloudflare/resource_cloudflare_ruleset.go @@ -378,6 +378,16 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} { rule["exposed_credential_check"] = exposedCredentialCheck } + if !reflect.ValueOf(r.Logging).IsNil() { + var logging []map[string]interface{} + + logging = append(logging, map[string]interface{}{ + "enabled": r.Logging.Enabled, + }) + + rule["logging"] = logging + } + rulesData = append(rulesData, rule) } @@ -619,6 +629,21 @@ func buildRulesetRulesFromResource(d *schema.ResourceData) ([]cloudflare.Ruleset } } + if len(resourceRule["logging"].([]interface{})) > 0 { + rule.Logging = &cloudflare.RulesetRuleLogging{} + for _, parameter := range resourceRule["logging"].([]interface{}) { + for pKey, pValue := range parameter.(map[string]interface{}) { + switch pKey { + case "enabled": + rule.Logging.Enabled = pValue.(*bool) + + default: + log.Printf("[DEBUG] unknown key encountered in buildRulesetRulesFromResource for logging: %s", pKey) + } + } + } + } + rule.Action = resourceRule["action"].(string) rule.Enabled = resourceRule["enabled"].(bool) diff --git a/cloudflare/resource_cloudflare_ruleset_test.go b/cloudflare/resource_cloudflare_ruleset_test.go index b5d7ab0d04..79209b3738 100644 --- a/cloudflare/resource_cloudflare_ruleset_test.go +++ b/cloudflare/resource_cloudflare_ruleset_test.go @@ -1260,6 +1260,47 @@ func TestAccCloudflareRuleset_ExposedCredentialCheck(t *testing.T) { }) } +func TestAccCloudflareRuleset_Logging(t *testing.T) { + // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the WAF + // service does not yet support the API tokens and it results in + // misleading state error messages. + if os.Getenv("CLOUDFLARE_API_TOKEN") != "" { + defer func(apiToken string) { + os.Setenv("CLOUDFLARE_API_TOKEN", apiToken) + }(os.Getenv("CLOUDFLARE_API_TOKEN")) + os.Setenv("CLOUDFLARE_API_TOKEN", "") + } + + t.Parallel() + rnd := generateRandomResourceName() + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + resourceName := "cloudflare_ruleset." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCloudflareRulesetDisableLoggingForSkipAction(rnd, "example disable logging for skip rule", accountID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", "example disable logging for skip rule"), + resource.TestCheckResourceAttr(resourceName, "description", "This ruleset includes a skip rule whose logging is disabled."), + resource.TestCheckResourceAttr(resourceName, "kind", "zone"), + resource.TestCheckResourceAttr(resourceName, "phase", "http_request_firewall_managed"), + + resource.TestCheckResourceAttr(resourceName, "rules.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action", "skip"), + resource.TestCheckResourceAttr(resourceName, "rules.0.expression", "true"), + resource.TestCheckResourceAttr(resourceName, "rules.0.description", "example disabled logging"), + resource.TestCheckResourceAttr(resourceName, "rules.0.logging.#", "1"), + + resource.TestCheckResourceAttr(resourceName, "rules.0.logging.0.enabled", "false"), + ), + }, + }, + }) +} + func TestAccCloudflareRuleset_ConditionallySetActionParameterVersion(t *testing.T) { // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the WAF // service does not yet support the API tokens and it results in @@ -2208,6 +2249,31 @@ func testAccCheckCloudflareRulesetExposedCredentialCheck(rnd, name, accountID st `, rnd, name, accountID) } +func testAccCheckCloudflareRulesetDisableLoggingForSkipAction(rnd, name, accountID string) string { + return fmt.Sprintf(` + resource "cloudflare_ruleset" "%[1]s" { + account_id = "%[3]s" + name = "%[2]s" + description = "This ruleset includes a skip rule whose logging is disabled." + kind = "zone" + phase = "http_request_firewall_managed" + + rules { + action = "skip" + action_parameters { + ruleset = "current" + } + expression = "true" + enabled = true + description = "example disabled logging" + logging { + enabled = false + } + } + } +`, rnd, name, accountID) +} + func testAccCloudflareRulesetConditionallySetActionParameterVersion_ExecuteAlone(rnd, accountID, domain string) string { return fmt.Sprintf(` resource "cloudflare_ruleset" "%[1]s" { diff --git a/cloudflare/schema_cloudflare_ruleset.go b/cloudflare/schema_cloudflare_ruleset.go index e6526b6f78..a7b405bd4b 100644 --- a/cloudflare/schema_cloudflare_ruleset.go +++ b/cloudflare/schema_cloudflare_ruleset.go @@ -354,6 +354,19 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema { }, }, }, + "logging": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, }, }, }, diff --git a/website/docs/r/ruleset.html.markdown b/website/docs/r/ruleset.html.markdown index f7776c1c72..bf2d2d6a38 100644 --- a/website/docs/r/ruleset.html.markdown +++ b/website/docs/r/ruleset.html.markdown @@ -222,6 +222,7 @@ The following arguments are supported: * `ratelimit` - (Optional) List of parameters that configure HTTP rate limiting behaviour (refer to the [nested schema](#nestedblock--ratelimiting-parameters)). * `response` - (Optional) List of parameters that configure the response given to end users (refer to the [nested schema](#nestedblock--response-parameters)). * `exposed_credential_check` - (Optional) List of parameters that configure exposed credential checks (refer to the [nested schema](#nestedblock--exposed-credential-check-parameters)). +* `logging` - (Optional) List parameters to configure how the rule generates logs (refer to the [nested schema](#nestedblock--logging)). * `ref` - (Read only) Rule reference. * `version`- (Read only) Version of the ruleset to deploy. @@ -241,6 +242,11 @@ The following arguments are supported: * `username_expression` - (Optional) Firewall Rules expression language based on Wireshark display filters for where to check for the "username" value. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language). * `password_expression` - (Optional) Firewall Rules expression language based on Wireshark display filters for where to check for the "password" value. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language). + +**Nested schema for `logging`** + +* `enabled` - (Optional) Override the default logging behavior when a rule is matched. + **Nested schema for `response`** @@ -248,12 +254,6 @@ The following arguments are supported: * `content_type` - (Optional) HTTP content type to send in the response. * `content` - (Optional) Body content to include in the response. - -**Nested schema for `exposed_credential_check`** - -* `username_expression` - (Optional) Firewall Rules expression language based on Wireshark display filters for where to check for the "username" value. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language). -* `password_expression` - (Optional) Firewall Rules expression language based on Wireshark display filters for where to check for the "password" value. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language). - **Nested schema for `action_parameters`** From 1e7b89e4bf3bde9168c2b6c670d004b0e79b7939 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Fri, 1 Apr 2022 15:19:56 +1100 Subject: [PATCH 2/3] convert rule.Logging.Enabled to pointer boolean --- cloudflare/resource_cloudflare_ruleset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflare/resource_cloudflare_ruleset.go b/cloudflare/resource_cloudflare_ruleset.go index 7a1ba4b3b0..1217758192 100644 --- a/cloudflare/resource_cloudflare_ruleset.go +++ b/cloudflare/resource_cloudflare_ruleset.go @@ -635,7 +635,7 @@ func buildRulesetRulesFromResource(d *schema.ResourceData) ([]cloudflare.Ruleset for pKey, pValue := range parameter.(map[string]interface{}) { switch pKey { case "enabled": - rule.Logging.Enabled = pValue.(*bool) + rule.Logging.Enabled = cloudflare.BoolPtr(pValue.(bool)) default: log.Printf("[DEBUG] unknown key encountered in buildRulesetRulesFromResource for logging: %s", pKey) From 160ed6759594cd337d6a49ad86284187c2caec3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Alberto=20Polo?= Date: Fri, 1 Apr 2022 11:01:29 +0200 Subject: [PATCH 3/3] Fix ruleset kind --- cloudflare/resource_cloudflare_ruleset_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudflare/resource_cloudflare_ruleset_test.go b/cloudflare/resource_cloudflare_ruleset_test.go index 79209b3738..9bade5a56c 100644 --- a/cloudflare/resource_cloudflare_ruleset_test.go +++ b/cloudflare/resource_cloudflare_ruleset_test.go @@ -1285,7 +1285,7 @@ func TestAccCloudflareRuleset_Logging(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", "example disable logging for skip rule"), resource.TestCheckResourceAttr(resourceName, "description", "This ruleset includes a skip rule whose logging is disabled."), - resource.TestCheckResourceAttr(resourceName, "kind", "zone"), + resource.TestCheckResourceAttr(resourceName, "kind", "root"), resource.TestCheckResourceAttr(resourceName, "phase", "http_request_firewall_managed"), resource.TestCheckResourceAttr(resourceName, "rules.#", "1"), @@ -2255,7 +2255,7 @@ func testAccCheckCloudflareRulesetDisableLoggingForSkipAction(rnd, name, account account_id = "%[3]s" name = "%[2]s" description = "This ruleset includes a skip rule whose logging is disabled." - kind = "zone" + kind = "root" phase = "http_request_firewall_managed" rules {