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
26 changes: 25 additions & 1 deletion docs/resources/ruleset.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,27 @@ resource "cloudflare_ruleset" "rate_limiting_example" {
}
}

# 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
}
}

# Change origin for an API route
resource "cloudflare_ruleset" "http_origin_example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
Expand Down Expand Up @@ -362,7 +383,7 @@ resource "cloudflare_ruleset" "redirect_from_list_example" {

- `kind` (String) Type of Ruleset to create. Available values: `custom`, `managed`, `root`, `schema`, `zone`.
- `name` (String) Name of the ruleset.
- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`.
- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_custom_errors`, `http_request_origin`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`.

### Optional

Expand Down Expand Up @@ -411,6 +432,9 @@ Optional:
- `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))
- `headers` (Block List) List of HTTP header modifications to perform in the ruleset rule. (see [below for nested schema](#nestedblock--rules--action_parameters--headers))
- `content` (String) Content of the served error response.
- `content_type` (String) Content-Type of the served error response.
- `status_code` (Number) HTTP status code of the served error response.
- `host_header` (String) Host Header that request origin receives.
- `id` (String) Identifier of the action parameter to modify.
- `increment` (Number)
Expand Down
14 changes: 13 additions & 1 deletion internal/provider/resource_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"sort"
"strings"

"github.com/cloudflare/cloudflare-go"
cloudflare "github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pkg/errors"
Expand Down Expand Up @@ -524,6 +524,9 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} {
"cache_key": cacheKeyFields,
"origin_error_page_passthru": r.ActionParameters.OriginErrorPagePassthru,
"from_list": fromListFields,
"content": r.ActionParameters.Content,
"content_type": r.ActionParameters.ContentType,
"status_code": r.ActionParameters.StatusCode,
})

rule["action_parameters"] = actionParameters
Expand Down Expand Up @@ -761,6 +764,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 = pValue.(uint16)

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", rnd+".terraform.cfapi.net"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.content_type", rnd+".terraform.cfapi.net"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.status_code", rnd+".terraform.cfapi.net"),
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 @@ -2340,6 +2382,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 = "%[1]s.terraform.cfapi.net"
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved
content_type = "%[1]s.terraform.cfapi.net"
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved
status_code = "%[1]s.terraform.cfapi.net"
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved
}
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
17 changes: 16 additions & 1 deletion internal/provider/schema_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package provider
import (
"fmt"

"github.com/cloudflare/cloudflare-go"
cloudflare "github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand Down Expand Up @@ -378,6 +378,21 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema {
},
},
},
"content": {
Type: schema.TypeString,
Optional: false,
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