diff --git a/.changelog/1688.txt b/.changelog/1688.txt new file mode 100644 index 0000000000..0289f8b758 --- /dev/null +++ b/.changelog/1688.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +cloudflare_managed_headers +``` \ No newline at end of file diff --git a/docs/resources/managed_headers.md b/docs/resources/managed_headers.md new file mode 100644 index 0000000000..80e23ad9a6 --- /dev/null +++ b/docs/resources/managed_headers.md @@ -0,0 +1,71 @@ +--- +page_title: "cloudflare_managed_headers Resource - Cloudflare" +subcategory: "" +description: |- + The Cloudflare Managed Headers https://developers.cloudflare.com/rules/transform/managed-transforms/ + allows you to add or remove some predefined headers to one's requests or origin responses. +--- + +# cloudflare_managed_headers (Resource) + +The [Cloudflare Managed Headers](https://developers.cloudflare.com/rules/transform/managed-transforms/) +allows you to add or remove some predefined headers to one's requests or origin responses. + +~> You can configure Managed Headers using the dashboard (https://api.cloudflare.com/#managed-headers-api-properties) +Terraform will override your configuration if it exists. + +## Example Usage + +```terraform +# Enable security headers using Managed Meaders +resource "cloudflare_managed_headers" "example" { + zone_id = "cb029e245cfdd66dc8d2e570d5dd3322" + + managed_request_headers { + id = "add_true_client_ip_headers" + enabled = true + } + + managed_response_headers { + id = "remove_x-powered-by_header" + enabled = true + } +} +``` + + +## Schema + +### Required + +- `zone_id` (String) The zone identifier to target for the resource. + +### Optional + +- `managed_request_headers` (Block Set) The list of managed request headers. (see [below for nested schema](#nestedblock--managed_request_headers)) +- `managed_response_headers` (Block Set) The list of managed response headers. (see [below for nested schema](#nestedblock--managed_response_headers)) + +### Read-Only + +- `id` (String) The ID of this resource. + + +### Nested Schema for `managed_request_headers` + +Required: + +- `enabled` (Boolean) Whether the headers rule is active. +- `id` (String) Unique headers rule identifier. + + + +### Nested Schema for `managed_response_headers` + +Required: + +- `enabled` (Boolean) Whether the headers rule is active. +- `id` (String) Unique headers rule identifier. + +## Import + +Import is not supported for this resource. diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index 4a428c2af5..877a578c86 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -274,7 +274,7 @@ resource "cloudflare_ruleset" "custom_fields_logging_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_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_main`, `http_request_sanitize`, `http_request_transform`, `http_request_origin`, `http_response_firewall_managed`, `http_response_headers_transform`, `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_request_origin`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`. ### Optional @@ -297,7 +297,7 @@ Required: Optional: -- `action` (String) Action to perform in the ruleset rule. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `managed_challenge`, `log`, `log_custom_field`, `rewrite`, `score`, `skip`, `route`. +- `action` (String) Action to perform in the ruleset rule. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `skip`. - `action_parameters` (Block List, Max: 1) List of parameters that configure the behavior of the ruleset rule action. (see [below for nested schema](#nestedblock--rules--action_parameters)) - `description` (String) Brief summary of the ruleset rule and its intended use. - `enabled` (Boolean) Whether the rule is active. @@ -324,7 +324,7 @@ Optional: - `matched_data` (Block List, Max: 1) List of properties to configure WAF payload logging. (see [below for nested schema](#nestedblock--rules--action_parameters--matched_data)) - `origin` (Block List, Max: 1) List of properties to change request origin. (see [below for nested schema](#nestedblock--rules--action_parameters--origin)) - `overrides` (Block List, Max: 1) List of override configurations to apply to the ruleset. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides)) -- `phases` (Set of 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_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_main`, `http_request_sanitize`, `http_request_transform`, `http_request_origin`, `http_response_firewall_managed`, `http_response_headers_transform`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`. +- `phases` (Set of 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`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`. - `products` (Set of String) Products to target with the actions. Available values: `bic`, `hot`, `ratelimit`, `securityLevel`, `uablock`, `waf`, `zonelockdown`. - `request_fields` (Set of String) List of request headers to include as part of custom fields logging, in lowercase. - `response` (Block List) List of parameters that configure the response given to end users. (see [below for nested schema](#nestedblock--rules--action_parameters--response)) @@ -368,7 +368,7 @@ Optional: Optional: -- `action` (String) Action to perform in the rule-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `managed_challenge`, `log`, `log_custom_field`, `rewrite`, `score`, `skip`, `route`. +- `action` (String) Action to perform in the rule-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `skip`. - `categories` (Block List) List of tag-based overrides. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides--categories)) - `enabled` (Boolean, Deprecated) Defines if the current ruleset-level override enables or disables the ruleset. - `rules` (Block List) List of rule-based overrides. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides--rules)) @@ -379,7 +379,7 @@ Optional: Optional: -- `action` (String) Action to perform in the tag-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `managed_challenge`, `log`, `log_custom_field`, `rewrite`, `score`, `skip`, `route`. +- `action` (String) Action to perform in the tag-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `skip`. - `category` (String) Tag name to apply the ruleset rule override to. - `enabled` (Boolean, Deprecated) Defines if the current tag-level override enables or disables the ruleset rules with the specified tag. - `status` (String) Defines if the current tag-level override enables or disables the ruleset rules with the specified tag. Available values: `enabled`, `disabled`. Defaults to `""`. @@ -390,7 +390,7 @@ Optional: Optional: -- `action` (String) Action to perform in the rule-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `managed_challenge`, `log`, `log_custom_field`, `rewrite`, `score`, `skip`, `route`. +- `action` (String) Action to perform in the rule-level override. Available values: `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `skip`. - `enabled` (Boolean, Deprecated) Defines if the current rule-level override enables or disables the rule. - `id` (String) Rule ID to apply the override to. - `score_threshold` (Number) Anomaly score threshold to apply in the ruleset rule override. Only applicable to modsecurity-based rulesets. diff --git a/examples/resources/managed_headers/resource.tf b/examples/resources/managed_headers/resource.tf new file mode 100644 index 0000000000..9340aa8d12 --- /dev/null +++ b/examples/resources/managed_headers/resource.tf @@ -0,0 +1,14 @@ +# Enable security headers using Managed Meaders +resource "cloudflare_managed_headers" "add_security_headers_example" { + zone_id = "cb029e245cfdd66dc8d2e570d5dd3322" + + managed_request_headers { + id = "add_true_client_ip_headers" + enabled = true + } + + managed_response_headers { + id = "remove_x-powered-by_header" + enabled = true + } +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index e64ede1823..031fce9b3c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -197,6 +197,7 @@ func New(version string) func() *schema.Provider { "cloudflare_logpush_job": resourceCloudflareLogpushJob(), "cloudflare_logpush_ownership_challenge": resourceCloudflareLogpushOwnershipChallenge(), "cloudflare_magic_firewall_ruleset": resourceCloudflareMagicFirewallRuleset(), + "cloudflare_managed_headers": resourceCloudflareManagedHeaders(), "cloudflare_notification_policy_webhooks": resourceCloudflareNotificationPolicyWebhooks(), "cloudflare_notification_policy": resourceCloudflareNotificationPolicy(), "cloudflare_origin_ca_certificate": resourceCloudflareOriginCACertificate(), diff --git a/internal/provider/resource_cloudflare_managed_headers.go b/internal/provider/resource_cloudflare_managed_headers.go new file mode 100644 index 0000000000..55a7ddc78e --- /dev/null +++ b/internal/provider/resource_cloudflare_managed_headers.go @@ -0,0 +1,183 @@ +package provider + +import ( + "context" + "errors" + "fmt" + + cloudflare "github.com/cloudflare/cloudflare-go" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareManagedHeaders() *schema.Resource { + return &schema.Resource{ + Schema: resourceCloudflareManagedHeadersSchema(), + CreateContext: resourceCloudflareManagedHeadersCreate, + ReadContext: resourceCloudflareManagedHeadersRead, + UpdateContext: resourceCloudflareManagedHeadersUpdate, + DeleteContext: resourceCloudflareManagedHeadersDelete, + SchemaVersion: 0, + Description: ` +The [Cloudflare Managed Headers](https://developers.cloudflare.com/rules/transform/managed-transforms/) +allows you to add or remove some predefined headers to one's requests or origin responses.`, + } +} + +func resourceCloudflareManagedHeadersCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + zoneID := d.Get("zone_id").(string) + d.SetId(zoneID) + return resourceCloudflareManagedHeadersUpdate(ctx, d, meta) +} + +func resourceCloudflareManagedHeadersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get("zone_id").(string) + headers, err := client.ListZoneManagedHeaders(ctx, cloudflare.ListManagedHeadersParams{ + ZoneID: zoneID, + }) + if err != nil { + return diag.FromErr(fmt.Errorf("error reading managed headers: %w", err)) + } + + // Filter out headers that are not enabled. This will eventually move into + // the API endpoint or the SDK. + var enabledRequestHeaders []cloudflare.ManagedHeader + var enabledResponseHeaders []cloudflare.ManagedHeader + + for _, header := range headers.ManagedRequestHeaders { + if header.Enabled { + enabledRequestHeaders = append(enabledRequestHeaders, header) + } + } + + for _, header := range headers.ManagedResponseHeaders { + if header.Enabled { + enabledResponseHeaders = append(enabledResponseHeaders, header) + } + } + + if err := d.Set("managed_request_headers", buildResourceFromManagedHeaders(enabledRequestHeaders)); err != nil { + return diag.FromErr(err) + } + if err := d.Set("managed_response_headers", buildResourceFromManagedHeaders(enabledResponseHeaders)); err != nil { + return diag.FromErr(err) + } + return nil +} + +func buildResourceFromManagedHeaders(headers []cloudflare.ManagedHeader) interface{} { + headersState := []map[string]interface{}{} + for _, header := range headers { + headersState = append(headersState, map[string]interface{}{ + "id": header.ID, + "enabled": header.Enabled, + }) + } + + return headersState +} + +func resourceCloudflareManagedHeadersUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get("zone_id").(string) + + mh, err := buildManagedHeadersFromResource(d) + if err != nil { + return diag.FromErr(fmt.Errorf("error building managed headers from resource: %w", err)) + } + if _, err := client.UpdateZoneManagedHeaders(ctx, cloudflare.UpdateManagedHeadersParams{ + ManagedHeaders: mh, + ZoneID: zoneID, + }); err != nil { + return diag.FromErr(fmt.Errorf("error updating managed headers: %w", err)) + } + return resourceCloudflareManagedHeadersRead(ctx, d, meta) +} + +// receives the resource config and builds a managed headers struct. +func buildManagedHeadersFromResource(d *schema.ResourceData) (cloudflare.ManagedHeaders, error) { + requestHeaders, ok := d.Get("managed_request_headers").(*schema.Set) + if !ok { + return cloudflare.ManagedHeaders{}, errors.New("unable to create interface array type assertion") + } + reqHeaders, err := buildManagedHeadersListFromResource(requestHeaders) + if err != nil { + return cloudflare.ManagedHeaders{}, err + } + + responseHeaders, ok := d.Get("managed_response_headers").(*schema.Set) + if !ok { + return cloudflare.ManagedHeaders{}, errors.New("unable to create interface array type assertion") + } + respHeaders, err := buildManagedHeadersListFromResource(responseHeaders) + if err != nil { + return cloudflare.ManagedHeaders{}, err + } + + return cloudflare.ManagedHeaders{ + ManagedRequestHeaders: reqHeaders, + ManagedResponseHeaders: respHeaders, + }, nil +} + +func buildManagedHeadersListFromResource(resource *schema.Set) ([]cloudflare.ManagedHeader, error) { + headers := make([]cloudflare.ManagedHeader, 0, len(resource.List())) + for _, header := range resource.List() { + h, ok := header.(map[string]interface{}) + if !ok { + return nil, errors.New("unable to create interface map type assertion for managed header") + } + id, ok := h["id"].(string) + if !ok { + return nil, errors.New("unable to create string type assertion for managed header ID") + } + enabled, ok := h["enabled"].(bool) + if !ok { + return nil, errors.New("unable to create bool type assertion for managed header enabled") + } + + if enabled { + headers = append(headers, cloudflare.ManagedHeader{ + ID: id, + Enabled: enabled, + }) + } + } + return headers, nil +} + +func resourceCloudflareManagedHeadersDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get("zone_id").(string) + + headers, err := client.ListZoneManagedHeaders(ctx, cloudflare.ListManagedHeadersParams{ + ZoneID: zoneID, + }) + if err != nil { + return diag.FromErr(fmt.Errorf("error reading managed headers: %w", err)) + } + + requestHeaders := make([]cloudflare.ManagedHeader, 0, len(headers.ManagedRequestHeaders)) + for _, header := range headers.ManagedRequestHeaders { + header.Enabled = false + requestHeaders = append(requestHeaders, header) + } + responseHeaders := make([]cloudflare.ManagedHeader, 0, len(headers.ManagedResponseHeaders)) + for _, header := range headers.ManagedResponseHeaders { + header.Enabled = false + responseHeaders = append(responseHeaders, header) + } + + if _, err := client.UpdateZoneManagedHeaders(ctx, cloudflare.UpdateManagedHeadersParams{ + ManagedHeaders: cloudflare.ManagedHeaders{ + ManagedRequestHeaders: requestHeaders, + ManagedResponseHeaders: responseHeaders, + }, + ZoneID: zoneID, + }); err != nil { + return diag.FromErr(fmt.Errorf("error deleting managed headers with ID %q: %w", d.Id(), err)) + } + + return nil +} diff --git a/internal/provider/resource_cloudflare_managed_headers_test.go b/internal/provider/resource_cloudflare_managed_headers_test.go new file mode 100644 index 0000000000..38a3900873 --- /dev/null +++ b/internal/provider/resource_cloudflare_managed_headers_test.go @@ -0,0 +1,119 @@ +package provider + +import ( + "context" + "fmt" + "os" + "testing" + + cloudflare "github.com/cloudflare/cloudflare-go" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/pkg/errors" +) + +func init() { + resource.AddTestSweepers("cloudflare_managed_headers", &resource.Sweeper{ + Name: "cloudflare_managed_headers", + F: testSweepCloudflareManagedHeaders, + }) +} + +func testSweepCloudflareManagedHeaders(r string) error { + ctx := context.Background() + client, clientErr := sharedClient() + if clientErr != nil { + tflog.Error(ctx, fmt.Sprintf("Failed to create Cloudflare client: %s", clientErr)) + } + + zone := os.Getenv("CLOUDFLARE_ZONE_ID") + if zone == "" { + return errors.New("CLOUDFLARE_ZONE_ID must be set") + } + + managedHeaders, err := client.ListZoneManagedHeaders(context.Background(), cloudflare.ListManagedHeadersParams{ + ZoneID: zoneID, + }) + if err != nil { + tflog.Error(ctx, fmt.Sprintf("Failed to fetch Cloudflare Zone Managed Headers: %s", err)) + } + + requestHeaders := make([]cloudflare.ManagedHeader, 0, len(managedHeaders.ManagedRequestHeaders)) + for _, h := range managedHeaders.ManagedRequestHeaders { + tflog.Info(ctx, fmt.Sprintf("Disabling Cloudflare Zone Managed Header ID: %s", h.ID)) + h.Enabled = false + requestHeaders = append(requestHeaders, h) + } + responseHeaders := make([]cloudflare.ManagedHeader, 0, len(managedHeaders.ManagedResponseHeaders)) + for _, h := range managedHeaders.ManagedResponseHeaders { + tflog.Info(ctx, fmt.Sprintf("Disabling Cloudflare Zone Managed Header ID: %s", h.ID)) + h.Enabled = false + responseHeaders = append(responseHeaders, h) + } + + _, err = client.UpdateZoneManagedHeaders(context.Background(), cloudflare.UpdateManagedHeadersParams{ + ManagedHeaders: cloudflare.ManagedHeaders{ + ManagedRequestHeaders: requestHeaders, + ManagedResponseHeaders: responseHeaders, + }, + ZoneID: zoneID, + }) + if err != nil { + tflog.Error(ctx, fmt.Sprintf("Failed to disable Cloudflare Zone Managed Headers: %s", err)) + } + + return nil +} + +func TestAccCloudflareManagedHeaders(t *testing.T) { + t.Parallel() + + rnd := generateRandomResourceName() + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + resourceName := "cloudflare_managed_headers." + rnd + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testAccCheckCloudflareManagedHeaders(rnd, zoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "zone_id", zoneID), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.0.%", "2"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.0.id", "add_true_client_ip_headers"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.1.%", "2"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.1.id", "add_visitor_location_headers"), + resource.TestCheckResourceAttr(resourceName, "managed_request_headers.1.enabled", "true"), + + resource.TestCheckResourceAttr(resourceName, "managed_response_headers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "managed_response_headers.0.%", "2"), + resource.TestCheckResourceAttr(resourceName, "managed_response_headers.0.id", "add_security_headers"), + resource.TestCheckResourceAttr(resourceName, "managed_response_headers.0.enabled", "true"), + ), + }, + }, + }) +} + +func testAccCheckCloudflareManagedHeaders(rnd, zoneID string) string { + return fmt.Sprintf(` + resource "cloudflare_managed_headers" "%[1]s" { + zone_id = "%[2]s" + managed_request_headers { + id = "add_true_client_ip_headers" + enabled = true + } + + managed_request_headers { + id = "add_visitor_location_headers" + enabled = true + } + + managed_response_headers { + id = "add_security_headers" + enabled = true + } + }`, rnd, zoneID) +} diff --git a/internal/provider/schema_cloudflare_managed_headers.go b/internal/provider/schema_cloudflare_managed_headers.go new file mode 100644 index 0000000000..9f9be8cea4 --- /dev/null +++ b/internal/provider/schema_cloudflare_managed_headers.go @@ -0,0 +1,51 @@ +package provider + +import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + +func resourceCloudflareManagedHeadersSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "zone_id": { + Description: "The zone identifier to target for the resource.", + Type: schema.TypeString, + Required: true, + }, + "managed_request_headers": { + Description: "The list of managed request headers", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "Unique headers rule identifier.", + }, + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "Whether the headers rule is active.", + }, + }, + }, + }, + "managed_response_headers": { + Description: "The list of managed response headers", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "Unique headers rule identifier.", + }, + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "Whether the headers rule is active.", + }, + }, + }, + }, + } +} diff --git a/templates/resources/managed_headers.md.tmpl b/templates/resources/managed_headers.md.tmpl new file mode 100644 index 0000000000..514e9f6ada --- /dev/null +++ b/templates/resources/managed_headers.md.tmpl @@ -0,0 +1,23 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" +subcategory: "" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +~> You can configure Managed Headers using the dashboard (https://api.cloudflare.com/#managed-headers-api-properties) +Terraform will override your configuration if it exists. + +## Example Usage + +{{ tffile (printf "%s%s%s" "examples/resources/" .Name "/resource.tf") }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +Import is not supported for this resource.