Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rulesets custom error responses #1794

Merged
merged 8 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/1794.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_ruleset: add support and configuration for `serve_errors` action
```
23 changes: 23 additions & 0 deletions docs/resources/ruleset.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,26 @@ resource "cloudflare_ruleset" "redirect_from_value_example" {
enabled = true
}
}

# Serve some custom error response
resource "cloudflare_ruleset" "http_custom_error_example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "Serve some error response"
description = "Serve some error response"
kind = "zone"
phase = "http_custom_errors"
rules {
action = "serve_error"
action_parameters {
content = "some error html"
content_type = "text/html"
status_code = "530"
}
expression = "(http.request.uri.path matches \"^/api/\")"
description = "serve some error response"
enabled = true
}
}
```

<!-- schema generated by tfplugindocs -->
Expand Down Expand Up @@ -432,6 +452,8 @@ Optional:
- `browser_ttl` (Block List, Max: 1) List of browser TTL parameters to apply to the request. (see [below for nested schema](#nestedblock--rules--action_parameters--browser_ttl))
- `cache` (Boolean) Whether to cache if expression matches.
- `cache_key` (Block List, Max: 1) List of cache key parameters to apply to the request. (see [below for nested schema](#nestedblock--rules--action_parameters--cache_key))
- `content` (String) Content of the custom error response.
- `content_type` (String) Content-Type of the custom error response.
- `cookie_fields` (Set of String) List of cookie values to include as part of custom fields logging.
- `edge_ttl` (Block List, Max: 1) List of edge TTL parameters to apply to the request. (see [below for nested schema](#nestedblock--rules--action_parameters--edge_ttl))
- `from_list` (Block List, Max: 1) Use a list to lookup information for the action. (see [below for nested schema](#nestedblock--rules--action_parameters--from_list))
Expand All @@ -455,6 +477,7 @@ Optional:
- `rulesets` (Set of String) List of managed WAF rule IDs to target. Only valid when the `"action"` is set to skip.
- `serve_stale` (Block List, Max: 1) List of serve stale parameters to apply to the request. (see [below for nested schema](#nestedblock--rules--action_parameters--serve_stale))
- `sni` (Block List, Max: 1) List of properties to manange Server Name Indication. (see [below for nested schema](#nestedblock--rules--action_parameters--sni))
- `status_code` (Number) HTTP status code of the custom error response.
- `uri` (Block List, Max: 1) List of URI properties to configure for the ruleset rule when performing URL rewrite transformations. (see [below for nested schema](#nestedblock--rules--action_parameters--uri))
- `version` (String) Version of the ruleset to deploy.

Expand Down
20 changes: 20 additions & 0 deletions examples/resources/cloudflare_ruleset/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,23 @@ resource "cloudflare_ruleset" "redirect_from_value_example" {
enabled = true
}
}

# Serve some custom error response
resource "cloudflare_ruleset" "http_custom_error_example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "Serve some error response"
description = "Serve some error response"
kind = "zone"
phase = "http_custom_errors"
rules {
action = "serve_error"
action_parameters {
content = "some error html"
content_type = "text/html"
status_code = "530"
}
expression = "(http.request.uri.path matches \"^/api/\")"
description = "serve some error response"
enabled = true
}
}
12 changes: 12 additions & 0 deletions internal/provider/resource_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} {
"origin_error_page_passthru": r.ActionParameters.OriginErrorPagePassthru,
"from_list": fromListFields,
"from_value": fromValueFields,
"content": r.ActionParameters.Content,
"content_type": r.ActionParameters.ContentType,
"status_code": r.ActionParameters.StatusCode,
})

rule["action_parameters"] = actionParameters
Expand Down Expand Up @@ -782,6 +785,15 @@ func buildRulesetRulesFromResource(d *schema.ResourceData) ([]cloudflare.Ruleset

rule.ActionParameters.Headers = headers

case "content":
rule.ActionParameters.Content = pValue.(string)

case "content_type":
rule.ActionParameters.ContentType = pValue.(string)

case "status_code":
rule.ActionParameters.StatusCode = uint16(pValue.(int))

case "host_header":
rule.ActionParameters.HostHeader = pValue.(string)

Expand Down
65 changes: 65 additions & 0 deletions internal/provider/resource_cloudflare_ruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,48 @@ func TestAccCloudflareRuleset_RateLimit(t *testing.T) {
})
}

func TestAccCloudflareRuleset_CustomErrors(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()
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
zoneName := os.Getenv("CLOUDFLARE_DOMAIN")
resourceName := "cloudflare_ruleset." + rnd

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareRulesetCustomErrors(rnd, "example HTTP custom error response", zoneID, zoneName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "example HTTP custom error response"),
resource.TestCheckResourceAttr(resourceName, "description", rnd+" ruleset description"),
resource.TestCheckResourceAttr(resourceName, "kind", "zone"),
resource.TestCheckResourceAttr(resourceName, "phase", "http_custom_errors"),

resource.TestCheckResourceAttr(resourceName, "rules.#", "1"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action", "serve_error"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.content", "my example error page"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.content_type", "text/plain"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.status_code", "530"),
resource.TestCheckResourceAttr(resourceName, "rules.0.expression", "(http.request.uri.path matches \"^/api/\")"),
resource.TestCheckResourceAttr(resourceName, "rules.0.description", "example http custom error response"),
),
},
},
})
}

func TestAccCloudflareRuleset_RequestOrigin(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
Expand Down Expand Up @@ -2372,6 +2414,29 @@ func testAccCheckCloudflareRulesetManagedWAFPayloadLogging(rnd, name, zoneID, zo
}`, rnd, name, zoneID, zoneName)
}

func testAccCheckCloudflareRulesetCustomErrors(rnd, name, zoneID, zoneName string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s" {
zone_id = "%[3]s"
name = "%[2]s"
description = "%[1]s ruleset description"
kind = "zone"
phase = "http_custom_errors"

rules {
action = "serve_error"
action_parameters {
content = "my example error page"
content_type = "text/plain"
status_code = "530"
}
expression = "(http.request.uri.path matches \"^/api/\")"
description = "example http custom error response"
enabled = true
}
}`, rnd, name, zoneID, zoneName)
}

func testAccCheckCloudflareRulesetOrigin(rnd, name, zoneID, zoneName string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s" {
Expand Down
15 changes: 15 additions & 0 deletions internal/provider/schema_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,21 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema {
},
},
},
"content": {
Type: schema.TypeString,
Optional: true,
Description: "Content of the custom error response",
},
"content_type": {
Type: schema.TypeString,
Optional: true,
Description: "Content-Type of the custom error response",
},
"status_code": {
Type: schema.TypeInt,
Optional: true,
Description: "HTTP status code of the custom error response",
},
"host_header": {
Type: schema.TypeString,
Optional: true,
Expand Down