diff --git a/.changelog/3337.txt b/.changelog/3337.txt
new file mode 100644
index 0000000000..ab82b5a77c
--- /dev/null
+++ b/.changelog/3337.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/zone_settings_override: deprecate `mobile_redirect` setting and include state migration to remove from local state. You should immediately remove the configuration from the resource to prevent permadiffs.
+```
diff --git a/.changelog/3353.txt b/.changelog/3353.txt
new file mode 100644
index 0000000000..d09c403abd
--- /dev/null
+++ b/.changelog/3353.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_access_application: Support configuring OIDC SaaS access token lifetime
+```
diff --git a/.changelog/3360.txt b/.changelog/3360.txt
new file mode 100644
index 0000000000..2d29d0e48e
--- /dev/null
+++ b/.changelog/3360.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.27.2 to 1.28.0
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.18 to 1.27.19
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.18 to 1.17.19
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.55.1 to 1.55.2
+```
diff --git a/.changelog/3362.txt b/.changelog/3362.txt
new file mode 100644
index 0000000000..53652f37b9
--- /dev/null
+++ b/.changelog/3362.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.28.0 to 1.29.0
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.19 to 1.27.20
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.19 to 1.17.20
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.55.2 to 1.56.0
+```
diff --git a/.changelog/3363.txt b/.changelog/3363.txt
new file mode 100644
index 0000000000..84955f9d70
--- /dev/null
+++ b/.changelog/3363.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go/v2 from 2.2.0 to 2.3.0
+```
diff --git a/.changelog/3364.txt b/.changelog/3364.txt
new file mode 100644
index 0000000000..b4f76bb03b
--- /dev/null
+++ b/.changelog/3364.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.29.0 to 1.30.0
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.20 to 1.27.21
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.20 to 1.17.21
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.56.0 to 1.56.1
+```
diff --git a/.changelog/3365.txt b/.changelog/3365.txt
new file mode 100644
index 0000000000..76498ec466
--- /dev/null
+++ b/.changelog/3365.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go from 0.97.0 to 0.98.0
+```
diff --git a/.changelog/3368.txt b/.changelog/3368.txt
new file mode 100644
index 0000000000..1f6e6f3ca7
--- /dev/null
+++ b/.changelog/3368.txt
@@ -0,0 +1,7 @@
+```release-note:bug
+resource/cloudflare_list_item: implement exact match for IP values to prevent overlapping IP prefixes from not being found
+```
+
+```release-note:bug
+resource/cloudflare_list_item: fix crash when not using `type = "redirect"` due to attempting to compare `nil`
+```
diff --git a/.changelog/3395.txt b/.changelog/3395.txt
new file mode 100644
index 0000000000..9356d7fcac
--- /dev/null
+++ b/.changelog/3395.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/go-retryablehttp from 0.7.4 to 0.7.7 in /tools
+```
diff --git a/.changelog/3404.txt b/.changelog/3404.txt
new file mode 100644
index 0000000000..47d6f519e6
--- /dev/null
+++ b/.changelog/3404.txt
@@ -0,0 +1,9 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.21 to 1.27.22
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.21 to 1.17.22
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.56.1 to 1.57.0
+```
diff --git a/.changelog/3412.txt b/.changelog/3412.txt
new file mode 100644
index 0000000000..6afd776d90
--- /dev/null
+++ b/.changelog/3412.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.0 to 1.30.1
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.22 to 1.27.23
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.22 to 1.17.23
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.57.0 to 1.57.1
+```
diff --git a/.changelog/3417.txt b/.changelog/3417.txt
new file mode 100644
index 0000000000..7118c8ccbf
--- /dev/null
+++ b/.changelog/3417.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_notification_policy: Add tunnel_name filter for Magic Health Checks
+```
\ No newline at end of file
diff --git a/.changelog/3429.txt b/.changelog/3429.txt
new file mode 100644
index 0000000000..7171db01cb
--- /dev/null
+++ b/.changelog/3429.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/aws/aws-sdk-go-v2/service/s3 from 1.57.1 to 1.58.0 in the aws group
+```
diff --git a/.changelog/3437.txt b/.changelog/3437.txt
new file mode 100644
index 0000000000..b32b00ddc7
--- /dev/null
+++ b/.changelog/3437.txt
@@ -0,0 +1,6 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.23 to 1.27.24
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.23 to 1.17.24
+```
diff --git a/.changelog/3438.txt b/.changelog/3438.txt
new file mode 100644
index 0000000000..f3443f18a2
--- /dev/null
+++ b/.changelog/3438.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go from 0.98.0 to 0.99.0
+```
diff --git a/.changelog/3441.txt b/.changelog/3441.txt
new file mode 100644
index 0000000000..6e52e6c6e8
--- /dev/null
+++ b/.changelog/3441.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_r2_bucket: add validation to location hint to prevent invalid values from drifting
+```
diff --git a/.changelog/3442.txt b/.changelog/3442.txt
new file mode 100644
index 0000000000..5798b9564f
--- /dev/null
+++ b/.changelog/3442.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump golang.org/x/net from 0.26.0 to 0.27.0
+```
diff --git a/.changelog/3443.txt b/.changelog/3443.txt
new file mode 100644
index 0000000000..e4decdfaf6
--- /dev/null
+++ b/.changelog/3443.txt
@@ -0,0 +1,3 @@
+```release-note:new-data-source
+cloudflare_gateway_categories
+```
diff --git a/.changelog/3445.txt b/.changelog/3445.txt
new file mode 100644
index 0000000000..a89a221a70
--- /dev/null
+++ b/.changelog/3445.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/terraform-plugin-framework from 1.9.0 to 1.10.0
+```
diff --git a/.changelog/3446.txt b/.changelog/3446.txt
new file mode 100644
index 0000000000..ebfe460d1f
--- /dev/null
+++ b/.changelog/3446.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/terraform-plugin-testing from 1.8.0 to 1.9.0
+```
diff --git a/.changelog/3447.txt b/.changelog/3447.txt
new file mode 100644
index 0000000000..888cce4d37
--- /dev/null
+++ b/.changelog/3447.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/terraform-plugin-framework-validators from 0.12.0 to 0.13.0
+```
diff --git a/.changelog/3449.txt b/.changelog/3449.txt
new file mode 100644
index 0000000000..ca2ff62a2d
--- /dev/null
+++ b/.changelog/3449.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.1 to 1.30.2
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.24 to 1.27.25
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.24 to 1.17.25
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.58.0 to 1.58.1
+```
diff --git a/.changelog/3463.txt b/.changelog/3463.txt
new file mode 100644
index 0000000000..f9e06659f2
--- /dev/null
+++ b/.changelog/3463.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_risk_behavior: fix bug where partial definition of risk behaviors resulted in a provider error
+```
diff --git a/.changelog/3468.txt b/.changelog/3468.txt
new file mode 100644
index 0000000000..07c55a31ab
--- /dev/null
+++ b/.changelog/3468.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare-access-application: fixes bug when updating self_hosted_domains
+```
diff --git a/.changelog/3469.txt b/.changelog/3469.txt
new file mode 100644
index 0000000000..dbb57a17dd
--- /dev/null
+++ b/.changelog/3469.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_access_application: Fix bug that was not cleaning the API when removing all ids from the 'policies' list
+```
\ No newline at end of file
diff --git a/.changelog/3470.txt b/.changelog/3470.txt
new file mode 100644
index 0000000000..7bcba170ff
--- /dev/null
+++ b/.changelog/3470.txt
@@ -0,0 +1,3 @@
+```release-note:new-data-source
+cloudflare_gateway_app_types
+```
diff --git a/.changelog/3473.txt b/.changelog/3473.txt
new file mode 100644
index 0000000000..f1562cd101
--- /dev/null
+++ b/.changelog/3473.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_teams_rules: add support for `ignore_cname_category_matches`
+```
diff --git a/.changelog/3480.txt b/.changelog/3480.txt
new file mode 100644
index 0000000000..ba5cc06a89
--- /dev/null
+++ b/.changelog/3480.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go/v2 from 2.3.0 to 2.4.0
+```
diff --git a/.changelog/3483.txt b/.changelog/3483.txt
new file mode 100644
index 0000000000..ffd1b9f935
--- /dev/null
+++ b/.changelog/3483.txt
@@ -0,0 +1,12 @@
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.2 to 1.30.3
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.25 to 1.27.27
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.25 to 1.17.27
+```
+```release-note:dependency
+provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.58.1 to 1.58.2
+```
diff --git a/.changelog/3488.txt b/.changelog/3488.txt
new file mode 100644
index 0000000000..efa7e5b3f7
--- /dev/null
+++ b/.changelog/3488.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_teams_list: add support for descriptions on list items
+```
diff --git a/.changelog/3492.txt b/.changelog/3492.txt
new file mode 100644
index 0000000000..8aa6ef4764
--- /dev/null
+++ b/.changelog/3492.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_device_posture_rules: added support for intune compliance_status values
+```
\ No newline at end of file
diff --git a/.changelog/3499.txt b/.changelog/3499.txt
new file mode 100644
index 0000000000..2eb3fbfebc
--- /dev/null
+++ b/.changelog/3499.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go from 0.99.0 to 0.100.0
+```
diff --git a/.changelog/3500.txt b/.changelog/3500.txt
new file mode 100644
index 0000000000..c988267909
--- /dev/null
+++ b/.changelog/3500.txt
@@ -0,0 +1,48 @@
+```release-note:note
+resource/cloudflare_worker_cron_trigger: deprecated in favour of `cloudflare_workers_cron_trigger` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_domain: deprecated in favour of `cloudflare_workers_domain` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_route: deprecated in favour of `cloudflare_workers_route` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_script: deprecated in favour of `cloudflare_workers_script` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_secret: deprecated in favour of `cloudflare_workers_secret` and will be removed in the next major version.
+```
+
+
+```release-note:note
+resource/cloudflare_workers_for_platforms_namespace: deprecated in favour of `cloudflare_workers_for_platforms_dispatch_namespace` and will be removed in the next major version.
+```
+
+```release-note:new-resource
+cloudflare_workers_secret
+```
+
+```release-note:new-resource
+cloudflare_workers_script
+```
+
+```release-note:new-resource
+cloudflare_workers_route
+```
+
+```release-note:new-resource
+cloudflare_workers_domain
+```
+
+```release-note:new-resource
+cloudflare_workers_cron_trigger
+```
+
+```release-note:new-resource
+cloudflare_workers_for_platforms_dispatch_namespace
+```
diff --git a/.changelog/3509.txt b/.changelog/3509.txt
new file mode 100644
index 0000000000..51bbe437b9
--- /dev/null
+++ b/.changelog/3509.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/cloudflare_record: `value` is now deprecated in favour of `content`
+```
diff --git a/.changelog/3511.txt b/.changelog/3511.txt
new file mode 100644
index 0000000000..7d4dac1b79
--- /dev/null
+++ b/.changelog/3511.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_teams_rule: Add `disable_clipboard_redirection` attribute to `BISOAdminControls`
+```
diff --git a/.changelog/3512.txt b/.changelog/3512.txt
new file mode 100644
index 0000000000..5a981eaac8
--- /dev/null
+++ b/.changelog/3512.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_device_posture_rule: add ability to create client_certificate_v2 posture rule
+```
\ No newline at end of file
diff --git a/.changelog/3513.txt b/.changelog/3513.txt
new file mode 100644
index 0000000000..2509093a28
--- /dev/null
+++ b/.changelog/3513.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_device_settings_policy: Add tunnel_protocol field for device policies
+```
\ No newline at end of file
diff --git a/.changelog/3515.txt b/.changelog/3515.txt
new file mode 100644
index 0000000000..5da02af7e7
--- /dev/null
+++ b/.changelog/3515.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_list_item: handle overlapping hostname `url_hostname`
+```
\ No newline at end of file
diff --git a/.changelog/3516.txt b/.changelog/3516.txt
new file mode 100644
index 0000000000..253705c36a
--- /dev/null
+++ b/.changelog/3516.txt
@@ -0,0 +1,7 @@
+```release-note:enhancement
+resource/hyperdrive_config: Add support for creating Hyperdrive over Access configs
+```
+
+```release-note:enhancement
+resource/hyperdrive_config: Add support for max_age and stale_while_revalidate in Hyperdrive Config caching settings
+```
diff --git a/.changelog/3519.txt b/.changelog/3519.txt
new file mode 100644
index 0000000000..ee91155c4a
--- /dev/null
+++ b/.changelog/3519.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/access_application: add `skip_app_launcher_login_page` flag to skip the App Launcher landing page
+```
diff --git a/.changelog/3521.txt b/.changelog/3521.txt
new file mode 100644
index 0000000000..213c1e9198
--- /dev/null
+++ b/.changelog/3521.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/zone_settings_override: deprecate `minify` setting and include state migration to remove from local state. You should immediately remove the configuration from the resource to prevent permadiffs. Automatic migration of user configuration can be handled with [Grit](https://docs.grit.io/cli/quickstart) by running `grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_zone_settings_override_remove_minify`
+```
diff --git a/.changelog/3540.txt b/.changelog/3540.txt
new file mode 100644
index 0000000000..7cfbd5a4bb
--- /dev/null
+++ b/.changelog/3540.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/cloudflare/cloudflare-go from 0.100.0 to 0.101.0
+```
diff --git a/.changelog/3556.txt b/.changelog/3556.txt
new file mode 100644
index 0000000000..573c67cf7e
--- /dev/null
+++ b/.changelog/3556.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/cloudflare_access_policy: remove deprecation notice related to precedence
+```
\ No newline at end of file
diff --git a/.changelog/3557.txt b/.changelog/3557.txt
new file mode 100644
index 0000000000..abd83a8ae6
--- /dev/null
+++ b/.changelog/3557.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/aws/aws-sdk-go-v2/service/s3 from 1.58.2 to 1.58.3 in the aws group
+```
diff --git a/.changelog/3563.txt b/.changelog/3563.txt
new file mode 100644
index 0000000000..e28cc4c104
--- /dev/null
+++ b/.changelog/3563.txt
@@ -0,0 +1,3 @@
+```release-note:new-resource
+cloudflare_zero_trust_risk_score_integration
+```
\ No newline at end of file
diff --git a/.changelog/3575.txt b/.changelog/3575.txt
new file mode 100644
index 0000000000..70e6b27837
--- /dev/null
+++ b/.changelog/3575.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/terraform-plugin-framework from 1.10.0 to 1.11.0
+```
diff --git a/.changelog/3576.txt b/.changelog/3576.txt
new file mode 100644
index 0000000000..13f549c071
--- /dev/null
+++ b/.changelog/3576.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump golang.org/x/net from 0.27.0 to 0.28.0
+```
diff --git a/.changelog/3579.txt b/.changelog/3579.txt
new file mode 100644
index 0000000000..629d1b1b8b
--- /dev/null
+++ b/.changelog/3579.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_access_policy: handle multiple okta idps in access policies
+```
diff --git a/.changelog/3583.txt b/.changelog/3583.txt
new file mode 100644
index 0000000000..2d9e04c7e3
--- /dev/null
+++ b/.changelog/3583.txt
@@ -0,0 +1,3 @@
+```release-note:dependency
+provider: bump github.com/hashicorp/terraform-plugin-testing from 1.9.0 to 1.10.0
+```
diff --git a/.changelog/3584.txt b/.changelog/3584.txt
new file mode 100644
index 0000000000..775f474b2f
--- /dev/null
+++ b/.changelog/3584.txt
@@ -0,0 +1,327 @@
+```release-note:note
+resource/cloudflare_access_application: deprecated in favour of `cloudflare_zero_trust_access_application` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_ca_certificate: deprecated in favour of `cloudflare_zero_trust_access_short_lived_certificate` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_custom_page: deprecated in favour of `cloudflare_zero_trust_access_custom_page` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_group: deprecated in favour of `cloudflare_zero_trust_access_group` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_identity_provider: deprecated in favour of `cloudflare_zero_trust_access_identity_provider` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_keys_configuration: deprecated in favour of `cloudflare_zero_trust_access_key_configuration` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_mutual_tls_certificate: deprecated in favour of `cloudflare_zero_trust_access_mtls_certificate` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_mutual_tls_hostname_settings: deprecated in favour of `cloudflare_zero_trust_access_mtls_hostname_settings` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_organization: deprecated in favour of `cloudflare_zero_trust_organization` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_policy: deprecated in favour of `cloudflare_zero_trust_access_policy` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_service_token: deprecated in favour of `cloudflare_zero_trust_access_service_token` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_access_tag: deprecated in favour of `cloudflare_zero_trust_access_tag` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_dex_test: deprecated in favour of `cloudflare_zero_trust_dex_test` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_managed_networks: deprecated in favour of `cloudflare_zero_trust_device_managed_networks` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_policy_certificates: deprecated in favour of `cloudflare_zero_trust_device_certificates` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_posture_integration: deprecated in favour of `cloudflare_zero_trust_device_posture_integration` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_posture_rule: deprecated in favour of `cloudflare_zero_trust_device_posture_rule` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_device_settings_policy: deprecated in favour of `cloudflare_zero_trust_device_profiles` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_dlp_profile: deprecated in favour of `cloudflare_zero_trust_dlp_profile` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_dlp_custom_profile: deprecated in favour of `cloudflare_zero_trust_dlp_custom_profile` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_dlp_predefined_profile: deprecated in favour of `cloudflare_zero_trust_dlp_predefined_profile` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_fallback_domain: deprecated in favour of `cloudflare_zero_trust_local_domain_fallback` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_gre_tunnel: deprecated in favour of `cloudflare_magic_wan_gre_tunnel` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_ipsec_tunnel: deprecated in favour of `cloudflare_magic_wan_ipsec_tunnel` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_risk_behavior: deprecated in favour of `cloudflare_zero_trust_risk_behavior` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_split_tunnel: deprecated in favour of `cloudflare_zero_trust_split_tunnels` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_static_route: deprecated in favour of `cloudflare_magic_wan_static_route` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_teams_account: deprecated in favour of `cloudflare_zero_trust_gateway_settings` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_teams_list: deprecated in favour of `cloudflare_zero_trust_list` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_teams_location: deprecated in favour of `cloudflare_zero_trust_dns_location` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_teams_proxy_endpoint: deprecated in favour of `cloudflare_zero_trust_gateway_proxy_endpoint` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_teams_rule: deprecated in favour of `cloudflare_zero_trust_gateway_policy` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_tunnel: deprecated in favour of `cloudflare_zero_trust_tunnel_cloudflared` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_tunnel_config: deprecated in favour of `cloudflare_zero_trust_tunnel_cloudflared_config` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_tunnel_route: deprecated in favour of `cloudflare_zero_trust_tunnel_route` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_tunnel_virtual_network: deprecated in favour of `cloudflare_zero_trust_tunnel_virtual_network` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_cron_trigger: deprecated in favour of `cloudflare_workers_cron_trigger` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_domain: deprecated in favour of `cloudflare_workers_custom_domain` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_script: deprecated in favour of `cloudflare_workers_script` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_worker_secret: deprecated in favour of `cloudflare_workers_secret` and will be removed in the next major version.
+```
+
+```release-note:note
+resource/cloudflare_workers_for_platforms_namespace: deprecated in favour of `cloudflare_workers_for_platforms_dispatch_namespace` and will be removed in the next major version.
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_application
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_short_lived_certificate
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_custom_page
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_group
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_identity_provider
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_key_configuration
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_mtls_certificate
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_mtls_hostname_settings
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_organization
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_policy
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_service_token
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_access_tag
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_dex_test
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_device_managed_networks
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_device_certificates
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_device_posture_integration
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_device_posture_rule
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_device_profiles
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_dlp_profile
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_dlp_custom_profile
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_dlp_predefined_profile
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_local_domain_fallback
+```
+
+```release-note:new-resource
+cloudflare_magic_wan_gre_tunnel
+```
+
+```release-note:new-resource
+cloudflare_magic_wan_ipsec_tunnel
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_risk_behavior
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_split_tunnels
+```
+
+```release-note:new-resource
+cloudflare_magic_wan_static_route
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_gateway_settings
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_list
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_dns_location
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_gateway_proxy_endpoint
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_gateway_policy
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_tunnel_cloudflared
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_tunnel_cloudflared_config
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_tunnel_route
+```
+
+```release-note:new-resource
+cloudflare_zero_trust_tunnel_virtual_network
+```
+
+```release-note:new-resource
+cloudflare_workers_cron_trigger
+```
+
+```release-note:new-resource
+cloudflare_workers_custom_domain
+```
+
+```release-note:new-resource
+cloudflare_workers_script
+```
+
+```release-note:new-resource
+cloudflare_workers_secret
+```
+
+```release-note:new-resource
+cloudflare_workers_for_platforms_dispatch_namespace
+```
diff --git a/.changelog/3622.txt b/.changelog/3622.txt
new file mode 100644
index 0000000000..ada8611a80
--- /dev/null
+++ b/.changelog/3622.txt
@@ -0,0 +1,3 @@
+```release-note:new-resource
+resource/cloud_connector_rules: register new resource for Cloud Connector API service
+```
diff --git a/.changelog/3674.txt b/.changelog/3674.txt
new file mode 100644
index 0000000000..9c2e8ccf57
--- /dev/null
+++ b/.changelog/3674.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/cloudflare_record: fix a bug that prematurely removed the ability to set the deprecated `value` field.
+```
diff --git a/.changelog/3699.txt b/.changelog/3699.txt
new file mode 100644
index 0000000000..511f0c19c8
--- /dev/null
+++ b/.changelog/3699.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_record: refactor validation to use `ExactlyOneOf` instead of custom logic
+```
diff --git a/.changelog/3704.txt b/.changelog/3704.txt
new file mode 100644
index 0000000000..6b17df4823
--- /dev/null
+++ b/.changelog/3704.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/hyperdrive_config: use hyperdrive_config id when updating resource
+```
\ No newline at end of file
diff --git a/.changelog/3740.txt b/.changelog/3740.txt
new file mode 100644
index 0000000000..a5296233a5
--- /dev/null
+++ b/.changelog/3740.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_zero_trust_access_group: Fix false deprecation warnings
+```
diff --git a/.changelog/3745.txt b/.changelog/3745.txt
new file mode 100644
index 0000000000..aed0119551
--- /dev/null
+++ b/.changelog/3745.txt
@@ -0,0 +1,3 @@
+```release-note:note
+resource/cloudflare_logpush_job: Deprecate `frequency` in favour of `max_upload_interval_seconds`
+```
diff --git a/.changelog/3764.txt b/.changelog/3764.txt
new file mode 100644
index 0000000000..ff65fb6d38
--- /dev/null
+++ b/.changelog/3764.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/cloudflare_device_posture_rule: Modify Tanium's eid_last_seen field to be relative instead of a timestamp value
+```
diff --git a/.changelog/3776.txt b/.changelog/3776.txt
new file mode 100644
index 0000000000..acdc8d72d4
--- /dev/null
+++ b/.changelog/3776.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+resource/cloudflare_record: handle scenarios where `content` and `value` are both being set in state and erroneously always thinking the `content` field is the source of truth
+```
diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml
index fedffe5008..a9926ec564 100644
--- a/.github/workflows/acceptance-tests.yml
+++ b/.github/workflows/acceptance-tests.yml
@@ -17,8 +17,8 @@ on:
- '.changelog/**'
jobs:
- build:
- name: Build
+ acceptance-tests:
+ name: Acceptance Tests
runs-on: ubuntu-latest
env:
diff --git a/.github/workflows/next-acceptance-tests.yml b/.github/workflows/next-acceptance-tests.yml
new file mode 100644
index 0000000000..a6033f3ebc
--- /dev/null
+++ b/.github/workflows/next-acceptance-tests.yml
@@ -0,0 +1,49 @@
+name: (next) Acceptance Tests
+concurrency:
+ group: next-acceptance-tests
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ acceptance-tests:
+ name: Acceptance Tests
+ runs-on: ubuntu-latest
+
+ env:
+ CLOUDFLARE_ACCOUNT_ID: f037e56e89293a057740de681ac9abbe
+ CLOUDFLARE_ALT_DOMAIN: terraform2.cfapi.net
+ CLOUDFLARE_ALT_ZONE_ID: b72110c08e3382597095c29ba7e661ea
+ CLOUDFLARE_DOMAIN: terraform.cfapi.net
+ CLOUDFLARE_EMAIL: terraform-acceptance-test@cfapi.net
+ CLOUDFLARE_ZONE_ID: 0da42c8d2132a9ddaf714f9e7c920711
+ CLOUDFLARE_MUTUAL_TLS_CERTIFICATE: "-----BEGIN CERTIFICATE-----\\nMIIF+DCCA+CgAwIBAgIUWc0b+WiKSZob8wl2g/ujewoKCvgwDQYJKoZIhvcNAQEN\\nBQAwgZMxCzAJBgNVBAYTAlVTMQwwCgYDVQQIEwNOL0ExDDAKBgNVBAcTA04vQTEl\\nMCMGA1UEChMcVGVycmFmb3JtIEFjY2VwdGFuY2UgVGVzdGluZzEMMAoGA1UECxMD\\nTi9BMTMwMQYDVQQDEypUZXJyYWZvcm0gQWNjZXB0YW5jZSBUZXN0aW5nIENBIDE2\\nMTgyODU5MjYwHhcNMjEwNDEzMDM0ODAwWhcNMjYwNDEyMDM0ODAwWjCBkzELMAkG\\nA1UEBhMCVVMxDDAKBgNVBAgTA04vQTEMMAoGA1UEBxMDTi9BMSUwIwYDVQQKExxU\\nZXJyYWZvcm0gQWNjZXB0YW5jZSBUZXN0aW5nMQwwCgYDVQQLEwNOL0ExMzAxBgNV\\nBAMTKlRlcnJhZm9ybSBBY2NlcHRhbmNlIFRlc3RpbmcgQ0EgMTYxODI4NTkyNjCC\\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBzwmNB8g3eVp8Sn30z0U21\\niEh/uwa+WLPEGj/F90mWg2EnW+yFvI9O8OETJAgmAQs39Z4ivt488uwLNVplshnW\\nU5J7BqNk9MlBeUZwj6omuS1CZMST/YNSzmIHV5LtyJBcFaEZ2TAi4Ql9f+M9Y5HD\\ncxofze5n5tfYzgB3/1lFLk7Vr5eVsqeH5QGOdKZAlsIHfTPS6TFDXP/zTInqCUz0\\njfuNkRy9Mqg55JREHVGMufHcT7oTNZiLU+4B/2EfYXJ9YD6JwntKnwB2IC+iOfW7\\nGc6QtAREPIlsH3yjmO0rPORrT/oAnnWZcAkkklR5XDnY7QwK5JQ3amN1aByXaPtS\\nmbIJNMDxE84AeTREAqR8PmsPK5drRHr3qpWk9nUOVGUaeXwPV+M2t3Xe1WSAQwpv\\nJup6PyE8O6KZGwbOiYme5KaKhxMB/ObzhajhTH9RQX7+RMwBzlL+/XTFDnd2B3Ep\\nyndNFUHN7fAAapNGjPUXzez01G52N9asE8312JRmLaOqGQ2sWMzr8UgRPw7ZYL4v\\nsdlqE2fxXddijGM3TEane6CiM3UdO1VcRAjvNFQjY5WQBUdAkj5+V790cxUQZiMR\\nwfmh4hePo7bqXt9RjAS7OeFGBz//H5tQf9wFj3yJTsvKS5bIwP86quR969FFU8nW\\na0zNkQLwWygqlhW/VlhxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\\nAf8EBTADAQH/MB0GA1UdDgQWBBT6PStM4ZTFmvpp6lASxuxOkNYZXzANBgkqhkiG\\n9w0BAQ0FAAOCAgEACIs9YskrLq3huQXsPDQhHBu8/SLQTAtkj5vtYf1uSq6MXx1k\\nj6nDzvixnLam/4HhrsJQyI3FjXnk5yNwaAVA1hQoVw0G2on4qk215fsIRJUKjlzK\\npUfW49TFWZ+DPlhBJ/dmHSZsxG940p4xWmNjo2aJ2CraCgP2ns+FfPxXqtpthf1y\\nVW5SxKhR9VYNLczXEz8fKvDTLictYYwQ/xFZjxPHpOdV8+DoL18brNKHN8Hs/Nk1\\nkzhKrDk8fReEX+jmpG7n/q973nJ31KIBxk85owv/BFgnWpC7HPY+waIH0xNr2iZA\\nOu1orlBiBYAqG8zDBq3AGVlxg8yUOc5bik9OhCIwYyT2RFmd6z4O36uIM3LEzJ64\\nJj8TTjOP/ktqu+GZrUrnIjfu7mlGvc4u22P8ILJ2AZe5ITp/uhMRJbGbJGEMCCH3\\nkAKIEDATrevGdmgWUpdj8RNBS7+BK98eN+vcDqtY4Sudri2TwTkMbAscraacqrSJ\\n4rJfjSywVr4oWXyd2P83Hl398X3x04E0Rc15+wrGvaCSN5i1gzc30fTlz1X8dJQ3\\nccaHajJlRVZfuCrFBk6m5YRL7AoG4iFfoOuDZZJpjr9nXEzEONhRR5QAG83yMedS\\nd8//SuQhuJQTxJW7UzkWaao+32gW/RvuQun0XtCNoow/kMVMOeSjKL9xioM=\\n-----END CERTIFICATE-----"
+ CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
+ # CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ # CLOUDFLARE_API_USER_SERVICE_KEY: ${{ secrets.CLOUDFLARE_API_USER_SERVICE_KEY }}
+ CLOUDFLARE_LOGPUSH_OWNERSHIP_TOKEN: ${{ secrets.CLOUDFLARE_LOGPUSH_OWNERSHIP_TOKEN }}
+ CLOUDFLARE_WORKSPACE_ONE_CLIENT_ID: d0ed71f01c884e8b94ec4e4d6639f609
+ CLOUDFLARE_WORKSPACE_ONE_CLIENT_SECRET: ${{ secrets.CLOUDFLARE_WORKSPACE_ONE_CLIENT_SECRET }}
+ CLOUDFLARE_WORKSPACE_ONE_API_URL: ${{ secrets.CLOUDFLARE_WORKSPACE_ONE_API_URL }}
+ CLOUDFLARE_WORKSPACE_ONE_AUTH_URL: ${{ secrets.CLOUDFLARE_WORKSPACE_ONE_AUTH_URL }}
+ CLOUDFLARE_PAGES_OWNER: jacobbednarz
+ CLOUDFLARE_PAGES_REPO: pages-example
+ CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
+ CLOUDFLARE_R2_ACCESS_KEY_SECRET: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_SECRET }}
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: next
+ - uses: actions/setup-go@v5
+ with:
+ go-version-file: 'go.mod'
+ id: go
+ - uses: actions/cache@v4
+ with:
+ path: ~/go/pkg/mod
+ key: ${{ runner.os }}-go${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
+ - run: go install gotest.tools/gotestsum@latest
+ - run: TF_ACC=1 gotestsum ./internal/services/... -run "^TestAccCloudflare" -count 1 -v
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b7f6b631a3..4852ec8cd5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -7,6 +7,23 @@ jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
+ - name: Cleanup unused directories and tools
+ run: |
+ sudo rm -rf \
+ "$AGENT_TOOLSDIRECTORY" \
+ /opt/google/chrome \
+ /opt/microsoft/msedge \
+ /opt/microsoft/powershell \
+ /opt/pipx \
+ /usr/lib/mono \
+ /usr/local/julia* \
+ /usr/local/lib/android \
+ /usr/local/lib/node_modules \
+ /usr/local/share/chromium \
+ /usr/local/share/powershell \
+ /usr/share/dotnet \
+ /usr/share/swift
+ df -h /
- name: Checkout
uses: actions/checkout@v4
with:
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index d561d1a402..1f4d79b610 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -4,6 +4,14 @@ on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
+ env:
+ CLOUDFLARE_ACCOUNT_ID: f037e56e89293a057740de681ac9abbe
+ CLOUDFLARE_ALT_DOMAIN: terraform2.cfapi.net
+ CLOUDFLARE_ALT_ZONE_ID: b72110c08e3382597095c29ba7e661ea
+ CLOUDFLARE_DOMAIN: terraform.cfapi.net
+ CLOUDFLARE_ZONE_ID: 0da42c8d2132a9ddaf714f9e7c920711
+ CLOUDFLARE_EMAIL: terraform-acceptance-test@cfapi.net
+ CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
steps:
- name: Check out code repository source code
uses: actions/checkout@v4
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 24907279e2..88e17655bd 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,3 +1,4 @@
+version: 2
builds:
- env:
# goreleaser does not work with CGO, it could also complicate
@@ -49,7 +50,7 @@ release:
changelog:
disable: true
snapshot:
- name_template: "{{.ShortCommit}}-dev"
+ version_template: "{{.ShortCommit}}-dev"
announce:
discord:
diff --git a/.grit/.gitignore b/.grit/.gitignore
new file mode 100644
index 0000000000..e4fdfb17c1
--- /dev/null
+++ b/.grit/.gitignore
@@ -0,0 +1,2 @@
+.gritmodules*
+*.log
diff --git a/.grit/patterns/cloudflare_record_deprecate_value_for_content.grit b/.grit/patterns/cloudflare_record_deprecate_value_for_content.grit
new file mode 100644
index 0000000000..0c68b45942
--- /dev/null
+++ b/.grit/patterns/cloudflare_record_deprecate_value_for_content.grit
@@ -0,0 +1,9 @@
+engine marzano(0.1)
+language hcl
+
+pattern cloudflare_record_deprecate_value_for_content() {
+ `value = $v` as $record => `content = $v` where $record <: and {
+ within `resource "cloudflare_record" $_ { $_ }`,
+ not within `data { $_ }`,
+ }
+}
diff --git a/.grit/patterns/cloudflare_zone_settings_override_remove_minify.grit b/.grit/patterns/cloudflare_zone_settings_override_remove_minify.grit
new file mode 100644
index 0000000000..f933a28d19
--- /dev/null
+++ b/.grit/patterns/cloudflare_zone_settings_override_remove_minify.grit
@@ -0,0 +1,8 @@
+engine marzano(0.1)
+language hcl
+
+pattern cloudflare_zone_settings_override_deprecate_minify() {
+ `minify { $_ }` as $minify => . where {
+ $minify <: within `resource "cloudflare_zone_settings_override" $_ { $_ }`
+ }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdb5122d7d..d71667ca1d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,244 @@
-## 4.36.0 (Unreleased)
+## 4.41.0 (Unreleased)
+
+## 4.40.0 (August 21st, 2024)
+
+NOTES:
+
+* resource/cloudflare_access_application: deprecated in favour of `cloudflare_zero_trust_access_application` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_ca_certificate: deprecated in favour of `cloudflare_zero_trust_access_short_lived_certificate` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_custom_page: deprecated in favour of `cloudflare_zero_trust_access_custom_page` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_group: deprecated in favour of `cloudflare_zero_trust_access_group` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_identity_provider: deprecated in favour of `cloudflare_zero_trust_access_identity_provider` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_keys_configuration: deprecated in favour of `cloudflare_zero_trust_access_key_configuration` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_mutual_tls_certificate: deprecated in favour of `cloudflare_zero_trust_access_mtls_certificate` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_mutual_tls_hostname_settings: deprecated in favour of `cloudflare_zero_trust_access_mtls_hostname_settings` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_organization: deprecated in favour of `cloudflare_zero_trust_organization` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_policy: deprecated in favour of `cloudflare_zero_trust_access_policy` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_service_token: deprecated in favour of `cloudflare_zero_trust_access_service_token` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_access_tag: deprecated in favour of `cloudflare_zero_trust_access_tag` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_dex_test: deprecated in favour of `cloudflare_zero_trust_dex_test` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_managed_networks: deprecated in favour of `cloudflare_zero_trust_device_managed_networks` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_policy_certificates: deprecated in favour of `cloudflare_zero_trust_device_certificates` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_posture_integration: deprecated in favour of `cloudflare_zero_trust_device_posture_integration` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_posture_rule: deprecated in favour of `cloudflare_zero_trust_device_posture_rule` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_device_settings_policy: deprecated in favour of `cloudflare_zero_trust_device_profiles` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_dlp_custom_profile: deprecated in favour of `cloudflare_zero_trust_dlp_custom_profile` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_dlp_predefined_profile: deprecated in favour of `cloudflare_zero_trust_dlp_predefined_profile` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_dlp_profile: deprecated in favour of `cloudflare_zero_trust_dlp_profile` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_fallback_domain: deprecated in favour of `cloudflare_zero_trust_local_domain_fallback` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_gre_tunnel: deprecated in favour of `cloudflare_magic_wan_gre_tunnel` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_ipsec_tunnel: deprecated in favour of `cloudflare_magic_wan_ipsec_tunnel` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_record: fix a bug that prematurely removed the ability to set the deprecated `value` field. ([#3674](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3674))
+* resource/cloudflare_risk_behavior: deprecated in favour of `cloudflare_zero_trust_risk_behavior` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_split_tunnel: deprecated in favour of `cloudflare_zero_trust_split_tunnels` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_static_route: deprecated in favour of `cloudflare_magic_wan_static_route` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_teams_account: deprecated in favour of `cloudflare_zero_trust_gateway_settings` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_teams_list: deprecated in favour of `cloudflare_zero_trust_list` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_teams_location: deprecated in favour of `cloudflare_zero_trust_dns_location` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_teams_proxy_endpoint: deprecated in favour of `cloudflare_zero_trust_gateway_proxy_endpoint` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_teams_rule: deprecated in favour of `cloudflare_zero_trust_gateway_policy` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_tunnel: deprecated in favour of `cloudflare_zero_trust_tunnel_cloudflared` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_tunnel_config: deprecated in favour of `cloudflare_zero_trust_tunnel_cloudflared_config` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_tunnel_route: deprecated in favour of `cloudflare_zero_trust_tunnel_route` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_tunnel_virtual_network: deprecated in favour of `cloudflare_zero_trust_tunnel_virtual_network` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_worker_cron_trigger: deprecated in favour of `cloudflare_workers_cron_trigger` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_worker_domain: deprecated in favour of `cloudflare_workers_custom_domain` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_worker_script: deprecated in favour of `cloudflare_workers_script` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_worker_secret: deprecated in favour of `cloudflare_workers_secret` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* resource/cloudflare_workers_for_platforms_namespace: deprecated in favour of `cloudflare_workers_for_platforms_dispatch_namespace` and will be removed in the next major version. ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+
+FEATURES:
+
+* **New Resource:** `cloudflare_magic_wan_gre_tunnel` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_magic_wan_ipsec_tunnel` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_magic_wan_static_route` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_workers_cron_trigger` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_workers_custom_domain` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_workers_for_platforms_dispatch_namespace` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_workers_script` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_workers_secret` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_application` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_custom_page` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_group` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_identity_provider` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_key_configuration` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_mtls_certificate` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_mtls_hostname_settings` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_policy` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_service_token` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_short_lived_certificate` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_access_tag` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_device_certificates` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_device_managed_networks` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_device_posture_integration` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_device_posture_rule` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_device_profiles` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_dex_test` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_dlp_custom_profile` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_dlp_predefined_profile` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_dlp_profile` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_dns_location` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_gateway_policy` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_gateway_proxy_endpoint` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_gateway_settings` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_list` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_local_domain_fallback` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_organization` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_risk_behavior` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_risk_score_integration` ([#3563](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3563))
+* **New Resource:** `cloudflare_zero_trust_split_tunnels` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_tunnel_cloudflared` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_tunnel_cloudflared_config` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_tunnel_route` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+* **New Resource:** `cloudflare_zero_trust_tunnel_virtual_network` ([#3584](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3584))
+
+ENHANCEMENTS:
+
+* resource/cloudflare_device_posture_rule: add ability to create client_certificate_v2 posture rule ([#3512](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3512))
+* resource/cloudflare_device_settings_policy: Add tunnel_protocol field for device policies ([#3513](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3513))
+
+BUG FIXES:
+
+* resource/cloudflare_access_policy: handle multiple okta idps in access policies ([#3579](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3579))
+* resource/cloudflare_record: refactor validation to use `ExactlyOneOf` instead of custom logic ([#3699](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3699))
+
+DEPENDENCIES:
+
+* provider: bump github.com/hashicorp/terraform-plugin-framework from 1.10.0 to 1.11.0 ([#3575](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3575))
+* provider: bump github.com/hashicorp/terraform-plugin-testing from 1.9.0 to 1.10.0 ([#3583](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3583))
+* provider: bump golang.org/x/net from 0.27.0 to 0.28.0 ([#3576](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3576))
+
+## 4.39.0 (August 7th, 2024)
+
+NOTES:
+
+* resource/cloudflare_access_policy: remove deprecation notice related to precedence ([#3556](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3556))
+* resource/cloudflare_record: `value` is now deprecated in favour of `content` ([#3509](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3509))
+* resource/cloudflare_worker_cron_trigger: deprecated in favour of `cloudflare_workers_cron_trigger` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/cloudflare_worker_domain: deprecated in favour of `cloudflare_workers_domain` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/cloudflare_worker_route: deprecated in favour of `cloudflare_workers_route` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/cloudflare_worker_script: deprecated in favour of `cloudflare_workers_script` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/cloudflare_worker_secret: deprecated in favour of `cloudflare_workers_secret` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/cloudflare_workers_for_platforms_namespace: deprecated in favour of `cloudflare_workers_for_platforms_dispatch_namespace` and will be removed in the next major version. ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* resource/zone_settings_override: deprecate `minify` setting and include state migration to remove from local state. You should immediately remove the configuration from the resource to prevent permadiffs. Automatic migration of user configuration can be handled with [Grit](https://docs.grit.io/cli/quickstart) by running `grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_zone_settings_override_remove_minify` ([#3521](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3521))
+
+FEATURES:
+
+* **New Data Source:** `cloudflare_gateway_app_types` ([#3470](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3470))
+* **New Resource:** `cloudflare_workers_cron_trigger` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* **New Resource:** `cloudflare_workers_domain` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* **New Resource:** `cloudflare_workers_for_platforms_dispatch_namespace` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* **New Resource:** `cloudflare_workers_route` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* **New Resource:** `cloudflare_workers_script` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+* **New Resource:** `cloudflare_workers_secret` ([#3500](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3500))
+
+ENHANCEMENTS:
+
+* resource/access_application: add `skip_app_launcher_login_page` flag to skip the App Launcher landing page ([#3519](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3519))
+* resource/cloudflare_device_posture_rules: added support for intune compliance_status values ([#3492](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3492))
+* resource/cloudflare_teams_rule: Add `disable_clipboard_redirection` attribute to `BISOAdminControls` ([#3511](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3511))
+* resource/hyperdrive_config: Add support for creating Hyperdrive over Access configs ([#3516](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3516))
+* resource/hyperdrive_config: Add support for max_age and stale_while_revalidate in Hyperdrive Config caching settings ([#3516](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3516))
+
+BUG FIXES:
+
+* resource/cloudflare_list_item: handle overlapping hostname `url_hostname` ([#3515](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3515))
+* resource/cloudflare_risk_behavior: fix bug where partial definition of risk behaviors resulted in a provider error ([#3463](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3463))
+
+DEPENDENCIES:
+
+* provider: bump github.com/aws/aws-sdk-go-v2/service/s3 from 1.58.2 to 1.58.3 in the aws group ([#3557](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3557))
+* provider: bump github.com/cloudflare/cloudflare-go from 0.100.0 to 0.101.0 ([#3540](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3540))
+* provider: bump github.com/cloudflare/cloudflare-go from 0.99.0 to 0.100.0 ([#3499](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3499))
+
+## 4.38.0 (July 24th, 2024)
+
+FEATURES:
+
+* **New Data Source:** `cloudflare_gateway_categories` ([#3443](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3443))
+
+ENHANCEMENTS:
+
+* resource/cloudflare_teams_list: add support for descriptions on list items ([#3488](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3488))
+* resource/cloudflare_teams_rules: add support for `ignore_cname_category_matches` ([#3473](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3473))
+
+BUG FIXES:
+
+* resource/cloudflare-access-application: fixes bug when updating self_hosted_domains ([#3468](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3468))
+* resource/cloudflare_access_application: Fix bug that was not cleaning the API when removing all ids from the 'policies' list ([#3469](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3469))
+
+DEPENDENCIES:
+
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.24 to 1.27.25 ([#3449](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3449))
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.25 to 1.27.27 ([#3483](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3483))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.24 to 1.17.25 ([#3449](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3449))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.25 to 1.17.27 ([#3483](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3483))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.58.0 to 1.58.1 ([#3449](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3449))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.58.1 to 1.58.2 ([#3483](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3483))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.1 to 1.30.2 ([#3449](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3449))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.2 to 1.30.3 ([#3483](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3483))
+* provider: bump github.com/cloudflare/cloudflare-go/v2 from 2.3.0 to 2.4.0 ([#3480](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3480))
+
+## 4.37.0 (July 11th, 2024)
+
+ENHANCEMENTS:
+
+* resource/cloudflare_notification_policy: Add tunnel_name filter for Magic Health Checks ([#3417](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3417))
+
+BUG FIXES:
+
+* resource/cloudflare_r2_bucket: add validation to location hint to prevent invalid values from drifting ([#3441](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3441))
+
+DEPENDENCIES:
+
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.21 to 1.27.22 ([#3404](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3404))
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.22 to 1.27.23 ([#3412](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3412))
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.23 to 1.27.24 ([#3437](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3437))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.21 to 1.17.22 ([#3404](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3404))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.22 to 1.17.23 ([#3412](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3412))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.23 to 1.17.24 ([#3437](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3437))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.56.1 to 1.57.0 ([#3404](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3404))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.57.0 to 1.57.1 ([#3412](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3412))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.30.0 to 1.30.1 ([#3412](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3412))
+* provider: bump github.com/aws/aws-sdk-go-v2/service/s3 from 1.57.1 to 1.58.0 in the aws group ([#3429](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3429))
+* provider: bump github.com/cloudflare/cloudflare-go from 0.98.0 to 0.99.0 ([#3438](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3438))
+* provider: bump github.com/hashicorp/terraform-plugin-framework from 1.9.0 to 1.10.0 ([#3445](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3445))
+* provider: bump github.com/hashicorp/terraform-plugin-framework-validators from 0.12.0 to 0.13.0 ([#3447](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3447))
+* provider: bump github.com/hashicorp/terraform-plugin-testing from 1.8.0 to 1.9.0 ([#3446](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3446))
+* provider: bump golang.org/x/net from 0.26.0 to 0.27.0 ([#3442](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3442))
+
+## 4.36.0 (June 26th, 2024)
+
+NOTES:
+
+* resource/zone_settings_override: deprecate `mobile_redirect` setting and include state migration to remove from local state. You should immediately remove the configuration from the resource to prevent permadiffs. ([#3337](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3337))
+
+ENHANCEMENTS:
+
+* resource/cloudflare_access_application: Support configuring OIDC SaaS access token lifetime ([#3353](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3353))
+
+BUG FIXES:
+
+* resource/cloudflare_list_item: fix crash when not using `type = "redirect"` due to attempting to compare `nil` ([#3368](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3368))
+* resource/cloudflare_list_item: implement exact match for IP values to prevent overlapping IP prefixes from not being found ([#3368](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3368))
+
+DEPENDENCIES:
+
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.18 to 1.27.19 ([#3360](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3360))
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.19 to 1.27.20 ([#3362](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3362))
+* provider: bump `github.com/aws/aws-sdk-go-v2/config` from 1.27.20 to 1.27.21 ([#3364](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3364))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.18 to 1.17.19 ([#3360](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3360))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.19 to 1.17.20 ([#3362](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3362))
+* provider: bump `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.20 to 1.17.21 ([#3364](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3364))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.55.1 to 1.55.2 ([#3360](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3360))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.55.2 to 1.56.0 ([#3362](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3362))
+* provider: bump `github.com/aws/aws-sdk-go-v2/service/s3` from 1.56.0 to 1.56.1 ([#3364](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3364))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.27.2 to 1.28.0 ([#3360](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3360))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.28.0 to 1.29.0 ([#3362](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3362))
+* provider: bump `github.com/aws/aws-sdk-go-v2` from 1.29.0 to 1.30.0 ([#3364](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3364))
+* provider: bump github.com/cloudflare/cloudflare-go from 0.97.0 to 0.98.0 ([#3365](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3365))
+* provider: bump github.com/cloudflare/cloudflare-go/v2 from 2.2.0 to 2.3.0 ([#3363](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3363))
+* provider: bump github.com/hashicorp/go-retryablehttp from 0.7.4 to 0.7.7 in /tools ([#3395](https://github.com/cloudflare/terraform-provider-cloudflare/issues/3395))
## 4.35.0 (June 12th, 2024)
diff --git a/docs/data-sources/gateway_app_types.md b/docs/data-sources/gateway_app_types.md
new file mode 100644
index 0000000000..028c3d868d
--- /dev/null
+++ b/docs/data-sources/gateway_app_types.md
@@ -0,0 +1,40 @@
+---
+page_title: "cloudflare_gateway_app_types Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this data source to retrieve all Gateway application types for an account.
+---
+
+# cloudflare_gateway_app_types (Data Source)
+
+Use this data source to retrieve all Gateway application types for an account.
+
+## Example Usage
+
+```terraform
+data "cloudflare_gateway_app_types" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account ID to fetch Gateway App Types from.
+
+### Read-Only
+
+- `app_types` (Attributes List) A list of Gateway App Types. (see [below for nested schema](#nestedatt--app_types))
+
+
+### Nested Schema for `app_types`
+
+Read-Only:
+
+- `application_type_id` (Number) The identifier for the application type of this app.
+- `description` (String) A short summary of the app type.
+- `id` (Number) The identifier for this app type. There is only one app type per ID.
+- `name` (String) The name of the app type.
+
+
diff --git a/docs/data-sources/gateway_categories.md b/docs/data-sources/gateway_categories.md
new file mode 100644
index 0000000000..ad1feee3cc
--- /dev/null
+++ b/docs/data-sources/gateway_categories.md
@@ -0,0 +1,53 @@
+---
+page_title: "cloudflare_gateway_categories Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this data source to retrieve all Gateway categories for an account.
+---
+
+# cloudflare_gateway_categories (Data Source)
+
+Use this data source to retrieve all Gateway categories for an account.
+
+## Example Usage
+
+```terraform
+data "cloudflare_gateway_categories" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account ID to fetch Gateway Categories from.
+
+### Read-Only
+
+- `categories` (Attributes List) A list of Gateway Categories. (see [below for nested schema](#nestedatt--categories))
+
+
+### Nested Schema for `categories`
+
+Read-Only:
+
+- `beta` (Boolean) True if the category is in beta and subject to change.
+- `class` (String) Which account types are allowed to create policies based on this category.
+- `description` (String) A short summary of domains in the category.
+- `id` (Number) The identifier for this category. There is only one category per ID.
+- `name` (String) The name of the category.
+- `subcategories` (Attributes List) A list of subcategories. (see [below for nested schema](#nestedatt--categories--subcategories))
+
+
+### Nested Schema for `categories.subcategories`
+
+Read-Only:
+
+- `beta` (Boolean) True if the subcategory is in beta and subject to change.
+- `class` (String) Which account types are allowed to create policies based on this subcategory.
+- `description` (String) A short summary of domains in the subcategory.
+- `id` (Number) The identifier for this subcategory. There is only one subcategory per ID.
+- `name` (String) The name of the subcategory.
+
+
diff --git a/docs/data-sources/zero_trust_access_application.md b/docs/data-sources/zero_trust_access_application.md
new file mode 100644
index 0000000000..451a5c7eea
--- /dev/null
+++ b/docs/data-sources/zero_trust_access_application.md
@@ -0,0 +1,28 @@
+---
+page_title: "cloudflare_zero_trust_access_application Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this data source to lookup a single Access Application https://developers.cloudflare.com/cloudflare-one/applications/
+---
+
+# cloudflare_zero_trust_access_application (Data Source)
+
+Use this data source to lookup a single [Access Application](https://developers.cloudflare.com/cloudflare-one/applications/)
+
+
+
+## Schema
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Must provide only one of `zone_id`, `account_id`.
+- `domain` (String) The primary hostname and path that Access will secure. Must provide only one of `name`, `domain`.
+- `name` (String) Friendly name of the Access Application. Must provide only one of `name`, `domain`.
+- `zone_id` (String) The zone identifier to target for the resource. Must provide only one of `zone_id`, `account_id`.
+
+### Read-Only
+
+- `aud` (String) Application Audience (AUD) Tag of the application.
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/data-sources/zero_trust_access_identity_provider.md b/docs/data-sources/zero_trust_access_identity_provider.md
new file mode 100644
index 0000000000..aac430b9f0
--- /dev/null
+++ b/docs/data-sources/zero_trust_access_identity_provider.md
@@ -0,0 +1,30 @@
+---
+page_title: "cloudflare_zero_trust_access_identity_provider Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this data source to lookup a single Access Identity Provider https://developers.cloudflare.com/cloudflare-one/identity/idp-integration by name.
+---
+
+# cloudflare_zero_trust_access_identity_provider (Data Source)
+
+Use this data source to lookup a single [Access Identity Provider](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration) by name.
+
+
+
+## Schema
+
+### Required
+
+- `name` (String) Access Identity Provider name to search for.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Must provide only one of `zone_id`, `account_id`.
+- `zone_id` (String) The zone identifier to target for the resource. Must provide only one of `zone_id`, `account_id`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `type` (String) Access Identity Provider Type.
+
+
diff --git a/docs/data-sources/zero_trust_tunnel_cloudflared.md b/docs/data-sources/zero_trust_tunnel_cloudflared.md
new file mode 100644
index 0000000000..9eff91aa5c
--- /dev/null
+++ b/docs/data-sources/zero_trust_tunnel_cloudflared.md
@@ -0,0 +1,32 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_cloudflared Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this datasource to lookup a tunnel in an account.
+---
+
+# cloudflare_zero_trust_tunnel_cloudflared (Data Source)
+
+Use this datasource to lookup a tunnel in an account.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `name` (String) Name of the tunnel. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `is_deleted` (Boolean) If true, only include deleted tunnels. If false, exclude deleted tunnels. If empty, all tunnels will be included. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) ID of the tunnel.
+- `remote_config` (Boolean) Whether the tunnel can be configured remotely from the Zero Trust dashboard.
+- `status` (String) The status of the tunnel. Available values: `inactive`, `degraded`, `healthy`, `down`.
+- `tunnel_type` (String) The type of the tunnel. Available values: `cfd_tunnel`, `warp_connector`.
+
+
diff --git a/docs/data-sources/zero_trust_tunnel_virtual_network.md b/docs/data-sources/zero_trust_tunnel_virtual_network.md
new file mode 100644
index 0000000000..c100c96158
--- /dev/null
+++ b/docs/data-sources/zero_trust_tunnel_virtual_network.md
@@ -0,0 +1,27 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_virtual_network Data Source - Cloudflare"
+subcategory: ""
+description: |-
+ Use this datasource to lookup a tunnel virtual network in an account.
+---
+
+# cloudflare_zero_trust_tunnel_virtual_network (Data Source)
+
+Use this datasource to lookup a tunnel virtual network in an account.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) The Virtual Network Name.
+
+### Read-Only
+
+- `comment` (String) The Virtual Network Comment.
+- `id` (String) The ID of this resource.
+- `is_default` (Boolean) If true, only include deleted virtual networks. If false, exclude deleted virtual networks. If empty, all virtual networks will be included.
+
+
diff --git a/docs/data-sources/zone.md b/docs/data-sources/zone.md
index 8f914aa3f8..65d7e04e0e 100644
--- a/docs/data-sources/zone.md
+++ b/docs/data-sources/zone.md
@@ -26,7 +26,7 @@ data "cloudflare_zone" "example" {
resource "cloudflare_record" "example" {
zone_id = data.cloudflare_zone.example.id
name = "www"
- value = "203.0.113.1"
+ content = "203.0.113.1"
type = "A"
proxied = true
}
diff --git a/docs/resources/access_application.md b/docs/resources/access_application.md
index ab968e65ff..a8d44fb735 100644
--- a/docs/resources/access_application.md
+++ b/docs/resources/access_application.md
@@ -80,13 +80,14 @@ resource "cloudflare_access_application" "staging_app" {
- `logo_url` (String) Image URL for the logo shown in the app launcher dashboard.
- `name` (String) Friendly name of the Access Application.
- `options_preflight_bypass` (Boolean) Allows options preflight requests to bypass Access authentication and go directly to the origin. Cannot turn on if cors_headers is set. Defaults to `false`.
-- `policies` (List of String) The policies associated with the application, in ascending order of precedence. When omitted, the application policies are not be updated. Warning: Do not use this field while you still have this application ID referenced as `application_id` in any `cloudflare_access_policy` resource, as it can result in an inconsistent state.
+- `policies` (List of String) The policies associated with the application, in ascending order of precedence. Warning: Do not use this field while you still have this application ID referenced as `application_id` in any `cloudflare_access_policy` resource, as it can result in an inconsistent state.
- `saas_app` (Block List, Max: 1) SaaS configuration for the Access Application. (see [below for nested schema](#nestedblock--saas_app))
- `same_site_cookie_attribute` (String) Defines the same-site cookie setting for access tokens. Available values: `none`, `lax`, `strict`.
- `scim_config` (Block List, Max: 1) Configuration for provisioning to this application via SCIM. This is currently in closed beta. (see [below for nested schema](#nestedblock--scim_config))
- `self_hosted_domains` (Set of String) List of domains that access will secure. Only present for self_hosted, vnc, and ssh applications. Always includes the value set as `domain`.
- `service_auth_401_redirect` (Boolean) Option to return a 401 status code in service authentication rules on failed requests. Defaults to `false`.
- `session_duration` (String) How often a user will be forced to re-authorise. Must be in the format `48h` or `2h45m`. Defaults to `24h`.
+- `skip_app_launcher_login_page` (Boolean) Option to skip the App Launcher landing page. Defaults to `false`.
- `skip_interstitial` (Boolean) Option to skip the authorization interstitial when using the CLI. Defaults to `false`.
- `tags` (Set of String) The itags associated with the application.
- `type` (String) The application type. Available values: `app_launcher`, `bookmark`, `biso`, `dash_sso`, `saas`, `self_hosted`, `ssh`, `vnc`, `warp`. Defaults to `self_hosted`.
@@ -138,6 +139,7 @@ Optional:
Optional:
+- `access_token_lifetime` (String) The lifetime of the Access Token after creation. Valid units are `m` and `h`. Must be greater than or equal to 1m and less than or equal to 24h.
- `allow_pkce_without_client_secret` (Boolean) Allow PKCE flow without a client secret.
- `app_launcher_url` (String) The URL where this applications tile redirects users.
- `auth_type` (String) **Modifying this attribute will force creation of a new resource.**
@@ -231,7 +233,7 @@ Optional:
Optional:
-- `lifetime` (String) How long a refresh token will be valid for after creation. Valid units are m,h,d. Must be longer than 1m.
+- `lifetime` (String) How long a refresh token will be valid for after creation. Valid units are `m`, `h` and `d`. Must be longer than 1m.
diff --git a/docs/resources/access_policy.md b/docs/resources/access_policy.md
index 3c6e453edb..7f2f0e077c 100644
--- a/docs/resources/access_policy.md
+++ b/docs/resources/access_policy.md
@@ -28,7 +28,6 @@ a particular resource.
resource "cloudflare_access_policy" "test_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "staging policy"
- precedence = "1"
decision = "allow"
include {
@@ -45,7 +44,6 @@ resource "cloudflare_access_policy" "test_policy" {
resource "cloudflare_access_policy" "test_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "staging policy"
- precedence = "1"
decision = "allow"
include {
@@ -69,12 +67,12 @@ resource "cloudflare_access_policy" "test_policy" {
### Optional
- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
-- `application_id` (String, Deprecated) The ID of the application the policy is associated with. Required when using `precedence`. **Modifying this attribute will force creation of a new resource.**
+- `application_id` (String) The ID of the application the policy is associated with. Required when using `precedence`. **Modifying this attribute will force creation of a new resource.**
- `approval_group` (Block List) (see [below for nested schema](#nestedblock--approval_group))
- `approval_required` (Boolean)
- `exclude` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--exclude))
- `isolation_required` (Boolean) Require this application to be served in an isolated browser for users matching this policy.
-- `precedence` (Number, Deprecated) The unique precedence for policies on a single application. Required when using `application_id`.
+- `precedence` (Number) The unique precedence for policies on a single application. Required when using `application_id`.
- `purpose_justification_prompt` (String) The prompt to display to the user for a justification for accessing the resource. Required when using `purpose_justification_required`.
- `purpose_justification_required` (Boolean) Whether to prompt the user for a justification for accessing the resource.
- `require` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--require))
diff --git a/docs/resources/cloud_connector_rules.md b/docs/resources/cloud_connector_rules.md
new file mode 100644
index 0000000000..6625c152da
--- /dev/null
+++ b/docs/resources/cloud_connector_rules.md
@@ -0,0 +1,61 @@
+---
+page_title: "cloudflare_cloud_connector_rules Resource - Cloudflare"
+subcategory: ""
+description: |-
+ The Cloud Connector Rules add link to doc resource allows you to create and manage cloud connector rules for a zone.
+---
+
+# cloudflare_cloud_connector_rules (Resource)
+
+The [Cloud Connector Rules](add link to doc) resource allows you to create and manage cloud connector rules for a zone.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_cloud_connector_rules" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+
+ rules {
+ description = "connect aws bucket"
+ enabled = true
+ expression = "http.uri"
+ provider = "aws_s3"
+ parameters {
+ host = "mystorage.s3.ams.amazonaws.com"
+ }
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `zone_id` (String) The zone identifier to target for the resource.
+
+### Optional
+
+- `rules` (Block Set) List of Cloud Connector Rules (see [below for nested schema](#nestedblock--rules))
+
+
+### Nested Schema for `rules`
+
+Required:
+
+- `expression` (String) Criteria for an HTTP request to trigger the cloud connector rule. Uses the Firewall Rules expression language based on Wireshark display filters.
+- `provider` (String) Type of provider. Available values: `aws_s3`, `cloudflare_r2`, `azure_storage`, `gcp_storage`
+
+Optional:
+
+- `description` (String) Brief summary of the cloud connector rule and its intended use.
+- `enabled` (Boolean) Whether the headers rule is active.
+- `parameters` (Block, Optional) Cloud Connector Rule Parameters (see [below for nested schema](#nestedblock--rules--parameters))
+
+
+### Nested Schema for `rules.parameters`
+
+Required:
+
+- `host` (String) Host parameter for cloud connector rule
+
+
diff --git a/docs/resources/device_posture_rule.md b/docs/resources/device_posture_rule.md
index 7bde7f4446..d798ec44d4 100644
--- a/docs/resources/device_posture_rule.md
+++ b/docs/resources/device_posture_rule.md
@@ -40,7 +40,7 @@ resource "cloudflare_device_posture_rule" "eaxmple" {
### Required
- `account_id` (String) The account identifier to target for the resource.
-- `type` (String) The device posture rule type. Available values: `serial_number`, `file`, `application`, `gateway`, `warp`, `domain_joined`, `os_version`, `disk_encryption`, `firewall`, `client_certificate`, `workspace_one`, `unique_client_id`, `crowdstrike_s2s`, `sentinelone`, `kolide`, `tanium_s2s`, `intune`, `sentinelone_s2s`.
+- `type` (String) The device posture rule type. Available values: `serial_number`, `file`, `application`, `gateway`, `warp`, `domain_joined`, `os_version`, `disk_encryption`, `firewall`, `client_certificate`, `client_certificate_v2`, `workspace_one`, `unique_client_id`, `crowdstrike_s2s`, `sentinelone`, `kolide`, `tanium_s2s`, `intune`, `sentinelone_s2s`.
### Optional
@@ -63,19 +63,22 @@ Optional:
- `active_threats` (Number) The number of active threats from SentinelOne.
- `certificate_id` (String) The UUID of a Cloudflare managed certificate.
- `check_disks` (Set of String) Specific volume(s) to check for encryption.
+- `check_private_key` (Boolean) Confirm the certificate was not imported from another device.
- `cn` (String) The common name for a certificate.
-- `compliance_status` (String) The workspace one device compliance status. Available values: `compliant`, `noncompliant`.
-- `connection_id` (String) The workspace one connection id.
+- `compliance_status` (String) The workspace one or intune device compliance status. `compliant` and `noncompliant` are values supported by both providers. `unknown`, `conflict`, `error`, `ingraceperiod` values are only supported by intune. Available values: `compliant`, `noncompliant`, `unknown`, `conflict`, `error`, `ingraceperiod`.
+- `connection_id` (String) The workspace one or intune connection id.
- `count_operator` (String) The count comparison operator for kolide. Available values: `>`, `>=`, `<`, `<=`, `==`.
- `domain` (String) The domain that the client must join.
-- `eid_last_seen` (String) The datetime a device last seen in RFC 3339 format from Tanium.
+- `eid_last_seen` (String) The time a device last seen in Tanium. Must be in the format `1h` or `30m`. Valid units are `d`, `h` and `m`.
- `enabled` (Boolean) True if the firewall must be enabled.
- `exists` (Boolean) Checks if the file should exist.
+- `extended_key_usage` (Set of String) List of values indicating purposes for which the certificate public key can be used. Available values: `clientAuth`, `emailProtection`.
- `id` (String) The Teams List id. Required for `serial_number` and `unique_client_id` rule types.
- `infected` (Boolean) True if SentinelOne device is infected.
- `is_active` (Boolean) True if SentinelOne device is active.
- `issue_count` (String) The number of issues for kolide.
- `last_seen` (String) The duration of time that the host was last seen from Crowdstrike. Must be in the format `1h` or `30m`. Valid units are `d`, `h` and `m`.
+- `locations` (Block List) List of locations to check for client certificate posture check. (see [below for nested schema](#nestedblock--certificate_locations))
- `network_status` (String) The network status from SentinelOne. Available values: `connected`, `disconnected`, `disconnecting`, `connecting`.
- `operator` (String) The version comparison operator. Available values: `>`, `>=`, `<`, `<=`, `==`.
- `os` (String) OS signal score from Crowdstrike. Value must be between 1 and 100.
@@ -103,6 +106,14 @@ Optional:
- `platform` (String) The platform of the device. Available values: `windows`, `mac`, `linux`, `android`, `ios`, `chromeos`.
+
+### Nested Schema for `locations`
+
+Optional:
+
+- `paths` (Set of String) List of paths to check for client certificate.
+- `trust_stores` (Set of String) List of trust stores to check for client certificate. Available values: `system`, `user`.
+
## Import
Import is supported using the following syntax:
diff --git a/docs/resources/device_settings_policy.md b/docs/resources/device_settings_policy.md
index e872a925cf..016c5da942 100644
--- a/docs/resources/device_settings_policy.md
+++ b/docs/resources/device_settings_policy.md
@@ -31,6 +31,7 @@ resource "cloudflare_device_settings_policy" "developer_warp_policy" {
service_mode_v2_mode = "warp"
service_mode_v2_port = 3000
exclude_office_ips = false
+ tunnel_protocol = "wireguard"
}
```
@@ -59,6 +60,7 @@ resource "cloudflare_device_settings_policy" "developer_warp_policy" {
- `service_mode_v2_port` (Number) The port to use for the proxy service mode. Required when using `service_mode_v2_mode`.
- `support_url` (String) The support URL that will be opened when sending feedback.
- `switch_locked` (Boolean) Enablement of the ZT client switch lock.
+- `tunnel_protocol` (String) Determines which tunnel protocol to use. Available values: `""`, `wireguard`, `masque`. Defaults to `wireguard`
### Read-Only
diff --git a/docs/resources/filter.md b/docs/resources/filter.md
index 8dbe976149..b17bc92490 100644
--- a/docs/resources/filter.md
+++ b/docs/resources/filter.md
@@ -13,8 +13,8 @@ Filter expressions that can be referenced across multiple features,
e.g. Firewall Rules. See [what is a filter](https://developers.cloudflare.com/firewall/api/cf-filters/what-is-a-filter/)
for more details and available fields and operators.
-~> `cloudflare_filter` is in a deprecation phase that will last for 14 months
- (July 1st, 2024). During this time period, this resource is still fully
+~> `cloudflare_filter` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still fully
supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users).
diff --git a/docs/resources/firewall_rule.md b/docs/resources/firewall_rule.md
index e1d03333be..3a42b92e20 100644
--- a/docs/resources/firewall_rule.md
+++ b/docs/resources/firewall_rule.md
@@ -20,8 +20,8 @@ rule creation.
Filter expressions needs to be created first before using Firewall
Rule.
-~> `cloudflare_firewall_rule` is in a deprecation phase that will last for 14
- months (July 1st, 2024). During this time period, this resource is still
+~> `cloudflare_firewall_rule` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still
fully supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users).
diff --git a/docs/resources/hyperdrive_config.md b/docs/resources/hyperdrive_config.md
index fd50dd894e..29776ea0ea 100644
--- a/docs/resources/hyperdrive_config.md
+++ b/docs/resources/hyperdrive_config.md
@@ -47,10 +47,15 @@ Required:
- `database` (String) The name of your origin database.
- `host` (String) The host (hostname or IP) of your origin database.
- `password` (String, Sensitive) The password of the Hyperdrive configuration.
-- `port` (Number) The port (default: 5432 for Postgres) of your origin database.
- `scheme` (String) Specifies the URL scheme used to connect to your origin database.
- `user` (String) The user of your origin database.
+Optional:
+
+- `access_client_id` (String) Client ID associated with the Cloudflare Access Service Token used to connect via Access.
+- `access_client_secret` (String) Client Secret associated with the Cloudflare Access Service Token used to connect via Access.
+- `port` (Number) The port (default: 5432 for Postgres) of your origin database.
+
### Nested Schema for `caching`
@@ -58,6 +63,8 @@ Required:
Optional:
- `disabled` (Boolean) Disable caching for this Hyperdrive configuration.
+- `max_age` (Number) Configure the `max_age` value of this Hyperdrive configuration.
+- `stale_while_revalidate` (Number) Disable caching for this Hyperdrive configuration.
## Import
diff --git a/docs/resources/logpush_job.md b/docs/resources/logpush_job.md
index 9269dd4bd2..b62d7a4bec 100644
--- a/docs/resources/logpush_job.md
+++ b/docs/resources/logpush_job.md
@@ -119,7 +119,7 @@ resource "cloudflare_logpush_job" "example_job" {
- `account_id` (String) The account identifier to target for the resource. Must provide only one of `account_id`, `zone_id`.
- `enabled` (Boolean) Whether to enable the job.
- `filter` (String) Use filters to select the events to include and/or remove from your logs. For more information, refer to [Filters](https://developers.cloudflare.com/logs/reference/logpush-api-configuration/filters/).
-- `frequency` (String) A higher frequency will result in logs being pushed on faster with smaller files. `low` frequency will push logs less often with larger files. Available values: `high`, `low`. Defaults to `high`.
+- `frequency` (String, Deprecated) A higher frequency will result in logs being pushed on faster with smaller files. `low` frequency will push logs less often with larger files. Available values: `high`, `low`. Defaults to `high`.
- `kind` (String) The kind of logpush job to create. Available values: `edge`, `instant-logs`, `""`.
- `logpull_options` (String) Configuration string for the Logshare API. It specifies things like requested fields and timestamp formats. See [Logpush options documentation](https://developers.cloudflare.com/logs/logpush/logpush-configuration-api/understanding-logpush-api/#options).
- `max_upload_bytes` (Number) The maximum uncompressed file size of a batch of logs. Value must be between 5MB and 1GB.
diff --git a/docs/resources/magic_wan_gre_tunnel.md b/docs/resources/magic_wan_gre_tunnel.md
new file mode 100644
index 0000000000..53b6d39044
--- /dev/null
+++ b/docs/resources/magic_wan_gre_tunnel.md
@@ -0,0 +1,59 @@
+---
+page_title: "cloudflare_magic_wan_gre_tunnel Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource, that manages GRE tunnels for Magic Transit.
+---
+
+# cloudflare_magic_wan_gre_tunnel (Resource)
+
+Provides a resource, that manages GRE tunnels for Magic Transit.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_magic_wan_gre_tunnel" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GRE_1"
+ customer_gre_endpoint = "203.0.113.1"
+ cloudflare_gre_endpoint = "203.0.113.2"
+ interface_address = "192.0.2.0/31"
+ description = "Tunnel for ISP X"
+ ttl = 64
+ mtu = 1476
+ health_check_enabled = true
+ health_check_target = "203.0.113.1"
+ health_check_type = "reply"
+}
+```
+
+## Schema
+
+### Required
+
+- `cloudflare_gre_endpoint` (String) The IP address assigned to the Cloudflare side of the GRE tunnel.
+- `customer_gre_endpoint` (String) The IP address assigned to the customer side of the GRE tunnel.
+- `interface_address` (String) 31-bit prefix (/31 in CIDR notation) supporting 2 hosts, one for each side of the tunnel.
+- `name` (String) Name of the GRE tunnel.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `description` (String) Description of the GRE tunnel intent.
+- `health_check_enabled` (Boolean) Specifies if ICMP tunnel health checks are enabled.
+- `health_check_target` (String) The IP address of the customer endpoint that will receive tunnel health checks.
+- `health_check_type` (String) Specifies the ICMP echo type for the health check. Available values: `request`, `reply`.
+- `mtu` (Number) Maximum Transmission Unit (MTU) in bytes for the GRE tunnel.
+- `ttl` (Number) Time To Live (TTL) in number of hops of the GRE tunnel.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_magic_wan_gre_tunnel.example /
+```
diff --git a/docs/resources/magic_wan_ipsec_tunnel.md b/docs/resources/magic_wan_ipsec_tunnel.md
new file mode 100644
index 0000000000..6dae58854b
--- /dev/null
+++ b/docs/resources/magic_wan_ipsec_tunnel.md
@@ -0,0 +1,66 @@
+---
+page_title: "cloudflare_magic_wan_ipsec_tunnel Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource, that manages IPsec tunnels for Magic Transit.
+---
+
+# cloudflare_magic_wan_ipsec_tunnel (Resource)
+
+Provides a resource, that manages IPsec tunnels for Magic Transit.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_magic_wan_ipsec_tunnel" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "IPsec_1"
+ customer_endpoint = "203.0.113.1"
+ cloudflare_endpoint = "203.0.113.1"
+ interface_address = "192.0.2.0/31"
+ description = "Tunnel for ISP X"
+ health_check_enabled = true
+ health_check_target = "203.0.113.1"
+ health_check_type = "reply"
+ psk = "asdf12341234"
+ allow_null_cipher = false
+}
+```
+
+## Schema
+
+### Required
+
+- `cloudflare_endpoint` (String) IP address assigned to the Cloudflare side of the IPsec tunnel.
+- `customer_endpoint` (String) IP address assigned to the customer side of the IPsec tunnel.
+- `interface_address` (String) 31-bit prefix (/31 in CIDR notation) supporting 2 hosts, one for each side of the tunnel.
+- `name` (String) Name of the IPsec tunnel.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `allow_null_cipher` (Boolean) Specifies if this tunnel may use a null cipher (ENCR_NULL) in Phase 2. Defaults to `false`.
+- `description` (String) An optional description of the IPsec tunnel.
+- `fqdn_id` (String) `remote_id` in the form of a fqdn. This value is generated by cloudflare.
+- `health_check_direction` (String) Specifies the direction for the health check. Available values: `unidirectional`, `bidirectional` Default: `unidirectional`.
+- `health_check_enabled` (Boolean) Specifies if ICMP tunnel health checks are enabled. Default: `true`.
+- `health_check_rate` (String) Specifies the ICMP rate for the health check. Available values: `low`, `mid`, `high` Default: `mid`.
+- `health_check_target` (String) The IP address of the customer endpoint that will receive tunnel health checks. Default: ``.
+- `health_check_type` (String) Specifies the ICMP echo type for the health check (`request` or `reply`). Available values: `request`, `reply` Default: `reply`.
+- `hex_id` (String) `remote_id` as a hex string. This value is generated by cloudflare.
+- `psk` (String, Sensitive) Pre shared key to be used with the IPsec tunnel. If left unset, it will be autogenerated.
+- `remote_id` (String) ID to be used while setting up the IPsec tunnel. This value is generated by cloudflare.
+- `replay_protection` (Boolean) Specifies if replay protection is enabled. Defaults to `false`.
+- `user_id` (String) `remote_id` in the form of an email address. This value is generated by cloudflare.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_magic_wan_ipsec_tunnel.example /
+```
diff --git a/docs/resources/magic_wan_static_route.md b/docs/resources/magic_wan_static_route.md
new file mode 100644
index 0000000000..a4f9a06660
--- /dev/null
+++ b/docs/resources/magic_wan_static_route.md
@@ -0,0 +1,61 @@
+---
+page_title: "cloudflare_magic_wan_static_route Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource, that manages Cloudflare static routes for Magic
+ Transit or Magic WAN. Static routes are used to route traffic
+ through GRE tunnels.
+---
+
+# cloudflare_magic_wan_static_route (Resource)
+
+Provides a resource, that manages Cloudflare static routes for Magic
+Transit or Magic WAN. Static routes are used to route traffic
+through GRE tunnels.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_magic_wan_static_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ description = "New route for new prefix 192.0.2.0/24"
+ prefix = "192.0.2.0/24"
+ nexthop = "10.0.0.0"
+ priority = 100
+ weight = 10
+ colo_names = [
+ "den01"
+ ]
+ colo_regions = [
+ "APAC"
+ ]
+}
+```
+
+## Schema
+
+### Required
+
+- `nexthop` (String) The nexthop IP address where traffic will be routed to.
+- `prefix` (String) Your network prefix using CIDR notation.
+- `priority` (Number) The priority for the static route.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `colo_names` (List of String) List of Cloudflare colocation regions for this static route.
+- `colo_regions` (List of String) List of Cloudflare colocation names for this static route.
+- `description` (String) Description of the static route.
+- `weight` (Number) The optional weight for ECMP routes. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_magic_wan_static_route.example /
+```
diff --git a/docs/resources/notification_policy.md b/docs/resources/notification_policy.md
index ba66f92e0f..fca4ba2229 100644
--- a/docs/resources/notification_policy.md
+++ b/docs/resources/notification_policy.md
@@ -134,6 +134,7 @@ Optional:
- `target_ip` (Set of String) Target ip to alert on for dos in CIDR notation.
- `target_zone_name` (Set of String) Target domain to alert on.
- `tunnel_id` (Set of String) Tunnel IDs to alert on.
+- `tunnel_name` (Set of String) Tunnel Names to alert on.
- `where` (Set of String) Filter for alert.
- `zones` (Set of String) A list of zone identifiers.
diff --git a/docs/resources/notification_policy_webhooks.md b/docs/resources/notification_policy_webhooks.md
index a550558960..c8ddce1e64 100644
--- a/docs/resources/notification_policy_webhooks.md
+++ b/docs/resources/notification_policy_webhooks.md
@@ -36,7 +36,7 @@ resource "cloudflare_notification_policy_webhooks" "example" {
- `created_at` (String) Timestamp of when the notification webhook was created.
- `id` (String) The ID of this resource.
-- `last_failure` (String) Timestamp of when the notification webhook last faiuled.
+- `last_failure` (String) Timestamp of when the notification webhook last failed.
- `last_success` (String) Timestamp of when the notification webhook was last successful.
- `type` (String)
diff --git a/docs/resources/r2_bucket.md b/docs/resources/r2_bucket.md
index 3b9e70bf62..0eea4c1b81 100644
--- a/docs/resources/r2_bucket.md
+++ b/docs/resources/r2_bucket.md
@@ -29,7 +29,7 @@ resource "cloudflare_r2_bucket" "example" {
### Optional
-- `location` (String) The location hint of the R2 bucket.
+- `location` (String) The location hint of the R2 bucket. Available values: `WNAM`, `ENAM`, `WEUR`, `EEUR`, `APAC`
### Read-Only
diff --git a/docs/resources/rate_limit.md b/docs/resources/rate_limit.md
index 141e114cf4..3b38f9430b 100644
--- a/docs/resources/rate_limit.md
+++ b/docs/resources/rate_limit.md
@@ -13,8 +13,8 @@ Provides a Cloudflare rate limit resource for a given zone. This can
be used to limit the traffic you receive zone-wide, or matching more
specific types of requests/responses.
-~> `cloudflare_rate_limit` is in a deprecation phase that will last for 14
- months (July 1st, 2024). During this time period, this resource is still
+~> `cloudflare_rate_limit` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still
fully supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/old-rate-limiting-deprecation/#relevant-changes-for-terraform-users).
diff --git a/docs/resources/record.md b/docs/resources/record.md
index 5880f2b1ad..fe03e3d2f9 100644
--- a/docs/resources/record.md
+++ b/docs/resources/record.md
@@ -16,7 +16,7 @@ Provides a Cloudflare record resource.
resource "cloudflare_record" "example" {
zone_id = var.cloudflare_zone_id
name = "terraform"
- value = "192.0.2.1"
+ content = "192.0.2.1"
type = "A"
ttl = 3600
}
@@ -51,13 +51,14 @@ resource "cloudflare_record" "_sip_tls" {
- `allow_overwrite` (Boolean) Allow creation of this record in Terraform to overwrite an existing record, if any. This does not affect the ability to update the record in Terraform and does not prevent other resources within Terraform or manual changes outside Terraform from overwriting this record. **This configuration is not recommended for most environments**. Defaults to `false`.
- `comment` (String) Comments or notes about the DNS record. This field has no effect on DNS responses.
-- `data` (Block List, Max: 1) Map of attributes that constitute the record value. Conflicts with `value`. (see [below for nested schema](#nestedblock--data))
+- `content` (String) The content of the record. Must provide only one of `data`, `content`, `value`.
+- `data` (Block List, Max: 1) Map of attributes that constitute the record value. Must provide only one of `data`, `content`, `value`. (see [below for nested schema](#nestedblock--data))
- `priority` (Number) The priority of the record.
- `proxied` (Boolean) Whether the record gets Cloudflare's origin protection.
- `tags` (Set of String) Custom tags for the DNS record.
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `ttl` (Number) The TTL of the record.
-- `value` (String) The value of the record. Conflicts with `data`.
+- `value` (String, Deprecated) The value of the record. Must provide only one of `data`, `content`, `value`.
### Read-Only
diff --git a/docs/resources/regional_hostname.md b/docs/resources/regional_hostname.md
index 96fcd9d8d4..9ccf0a03d9 100644
--- a/docs/resources/regional_hostname.md
+++ b/docs/resources/regional_hostname.md
@@ -17,7 +17,7 @@ Provides a Data Localization Suite Regional Hostname.
resource "cloudflare_record" "example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "example.com"
- value = "192.0.2.1"
+ content = "192.0.2.1"
type = "A"
ttl = 3600
}
diff --git a/docs/resources/risk_score_integration.md b/docs/resources/risk_score_integration.md
new file mode 100644
index 0000000000..a6a700a9a4
--- /dev/null
+++ b/docs/resources/risk_score_integration.md
@@ -0,0 +1,32 @@
+---
+page_title: "cloudflare_zero_trust_risk_score_integration Resource - Cloudflare"
+subcategory: ""
+description: |-
+ The Risk Score Integration https://developers.cloudflare.com/cloudflare-one/insights/risk-score/#send-risk-score-to-okta resource allows you to transmit changes in User Risk Score to a specified vendor such as Okta.
+---
+
+# cloudflare_zero_trust_risk_score_integration (Resource)
+
+The [Risk Score Integration](https://developers.cloudflare.com/cloudflare-one/insights/risk-score/#send-risk-score-to-okta) resource allows you to transmit changes in User Risk Score to a specified vendor such as Okta.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `integration_type` (String) The type of integration, e.g. 'Okta'. Full list of allowed values can be found here: https://developers.cloudflare.com/api/operations/dlp-zt-risk-score-integration-create#request-body
+- `tenant_url` (String) The base url of the tenant, e.g. 'https://tenant.okta.com'. Must be your Okta Tenant URL and not your custom domain.
+
+### Optional
+
+- `active` (Boolean) Whether this integration is enabled. If disabled, no risk changes will be exported to the third-party.
+- `reference_id` (String) A reference id that can be supplied by the client. Currently this should be set to the Access-Okta IDP ID (a UUIDv4). If omitted, a random UUIDv4 is used. https://developers.cloudflare.com/api/operations/access-identity-providers-get-an-access-identity-provider
+
+### Read-Only
+
+- `id` (String) The identifier of this resource.
+- `well_known_url` (String) The URL for the Shared Signals Framework configuration, e.g. '/.well-known/sse-configuration/{integration_uuid}/'. https://openid.net/specs/openid-sse-framework-1_0.html#rfc.section.6.2.1
+
+
diff --git a/docs/resources/split_tunnel.md b/docs/resources/split_tunnel.md
index d360ef02b7..1dc9e417f0 100644
--- a/docs/resources/split_tunnel.md
+++ b/docs/resources/split_tunnel.md
@@ -38,6 +38,7 @@ resource "cloudflare_split_tunnel" "example_split_tunnel_include" {
resource "cloudflare_device_settings_policy" "developer_warp_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "Developers"
+ description = "Developers WARP settings policy description"
precedence = 10
match = "any(identity.groups.name[*] in {\"Developers\"})"
switch_locked = true
@@ -57,7 +58,7 @@ resource "cloudflare_split_tunnel" "example_device_settings_policy_split_tunnel_
# Including *.example.com in WARP routes for a particular device policy
resource "cloudflare_split_tunnel" "example_split_tunnel_include" {
account_id = "f037e56e89293a057740de681ac9abbe"
- policy_id = cloudflare_device_policy.developer_warp_policy.id
+ policy_id = cloudflare_device_settings_policy.developer_warp_policy.id
mode = "include"
tunnels {
host = "*.example.com"
diff --git a/docs/resources/teams_list.md b/docs/resources/teams_list.md
index c72ed85ac2..878cb568e5 100644
--- a/docs/resources/teams_list.md
+++ b/docs/resources/teams_list.md
@@ -37,11 +37,20 @@ resource "cloudflare_teams_list" "example" {
- `description` (String) The description of the teams list.
- `items` (Set of String) The items of the teams list.
+- `items_with_description` (Set of Object) The items of the teams list that has explicit description. (see [below for nested schema](#nestedatt--items_with_description))
### Read-Only
- `id` (String) The ID of this resource.
+
+### Nested Schema for `items_with_description`
+
+Optional:
+
+- `description` (String)
+- `value` (String)
+
## Import
Import is supported using the following syntax:
diff --git a/docs/resources/teams_rule.md b/docs/resources/teams_rule.md
index 1c37b881bb..b2fc381208 100644
--- a/docs/resources/teams_rule.md
+++ b/docs/resources/teams_rule.md
@@ -66,6 +66,7 @@ Optional:
- `check_session` (Block List, Max: 1) Configure how session check behaves. (see [below for nested schema](#nestedblock--rule_settings--check_session))
- `dns_resolvers` (Block List, Max: 1) Add your own custom resolvers to route queries that match the resolver policy. Cannot be used when resolve_dns_through_cloudflare is set. DNS queries will route to the address closest to their origin. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers))
- `egress` (Block List, Max: 1) Configure how Proxy traffic egresses. Can be set for rules with Egress action and Egress filter. Can be omitted to indicate local egress via Warp IPs. (see [below for nested schema](#nestedblock--rule_settings--egress))
+- `ignore_cname_category_matches` (Boolean) Set to true, to ignore the category matches at CNAME domains in a response.
- `insecure_disable_dnssec_validation` (Boolean) Disable DNSSEC validation (must be Allow rule).
- `ip_categories` (Boolean) Turns on IP category based filter on dns if the rule contains dns category checks.
- `l4override` (Block List, Max: 1) Settings to forward layer 4 traffic. (see [below for nested schema](#nestedblock--rule_settings--l4override))
@@ -89,6 +90,7 @@ Required:
Optional:
+- `disable_clipboard_redirection` (Boolean) Disable clipboard redirection.
- `disable_copy_paste` (Boolean) Disable copy-paste.
- `disable_download` (Boolean) Disable download.
- `disable_keyboard` (Boolean) Disable keyboard usage.
@@ -110,8 +112,8 @@ Required:
Optional:
-- `ipv4` (Block List) IPv4 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv4))
-- `ipv6` (Block List) IPv6 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv6))
+- `ipv4` (Block List, Max: 10) IPv4 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv4))
+- `ipv6` (Block List, Max: 10) IPv6 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv6))
### Nested Schema for `rule_settings.dns_resolvers.ipv4`
diff --git a/docs/resources/tunnel_config.md b/docs/resources/tunnel_config.md
index 9d4b210c58..4c02ee5674 100644
--- a/docs/resources/tunnel_config.md
+++ b/docs/resources/tunnel_config.md
@@ -12,7 +12,7 @@ Provides a Cloudflare Tunnel configuration resource.
## Example Usage
```terraform
-resource "cloudflare_tunnel" "example_tunnel" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example_tunnel" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_tunnel"
secret = "<32 character secret>"
@@ -20,7 +20,7 @@ resource "cloudflare_tunnel" "example_tunnel" {
resource "cloudflare_tunnel_config" "example_config" {
account_id = "f037e56e89293a057740de681ac9abbe"
- tunnel_id = cloudflare_tunnel.example_tunnel.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.example_tunnel.id
config {
warp_routing {
diff --git a/docs/resources/tunnel_route.md b/docs/resources/tunnel_route.md
index 1e7378e391..63f83d215f 100644
--- a/docs/resources/tunnel_route.md
+++ b/docs/resources/tunnel_route.md
@@ -17,7 +17,7 @@ Cloudflare Tunnels.
```terraform
# Tunnel route
-resource "cloudflare_tunnel_route" "example" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415"
network = "192.0.2.24/32"
@@ -26,15 +26,15 @@ resource "cloudflare_tunnel_route" "example" {
}
# Tunnel with tunnel route
-resource "cloudflare_tunnel" "tunnel" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "tunnel" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "my_tunnel"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-resource "cloudflare_tunnel_route" "example" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
- tunnel_id = cloudflare_tunnel.tunnel.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.tunnel.id
network = "192.0.2.24/32"
comment = "New tunnel route for documentation"
virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
diff --git a/docs/resources/worker_cron_trigger.md b/docs/resources/worker_cron_trigger.md
index e977b42eb7..2320137d97 100644
--- a/docs/resources/worker_cron_trigger.md
+++ b/docs/resources/worker_cron_trigger.md
@@ -18,7 +18,7 @@ maintenance or calling third-party APIs to collect up-to-date data.
## Example Usage
```terraform
-resource "cloudflare_worker_script" "example_script" {
+resource "cloudflare_workers_script" "example_script" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example-script"
content = file("path/to/my.js")
@@ -26,7 +26,7 @@ resource "cloudflare_worker_script" "example_script" {
resource "cloudflare_worker_cron_trigger" "example_trigger" {
account_id = "f037e56e89293a057740de681ac9abbe"
- script_name = cloudflare_worker_script.example_script.name
+ script_name = cloudflare_workers_script.example_script.name
schedules = [
"*/5 * * * *", # every 5 minutes
"10 7 * * mon-fri", # 7:10am every weekday
diff --git a/docs/resources/worker_route.md b/docs/resources/worker_route.md
index 89e8b6298b..e3b8ebcf82 100644
--- a/docs/resources/worker_route.md
+++ b/docs/resources/worker_route.md
@@ -16,11 +16,11 @@ Provides a Cloudflare worker route resource. A route will also require a `cloudf
resource "cloudflare_worker_route" "my_route" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
pattern = "example.com/*"
- script_name = cloudflare_worker_script.my_script.name
+ script_name = cloudflare_workers_script.my_script.name
}
-resource "cloudflare_worker_script" "my_script" {
- # see "cloudflare_worker_script" documentation ...
+resource "cloudflare_workers_script" "my_script" {
+ # see "cloudflare_workers_script" documentation ...
}
```
diff --git a/docs/resources/workers_cron_trigger.md b/docs/resources/workers_cron_trigger.md
new file mode 100644
index 0000000000..e4b3e022e1
--- /dev/null
+++ b/docs/resources/workers_cron_trigger.md
@@ -0,0 +1,55 @@
+---
+page_title: "cloudflare_workers_cron_trigger Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Worker Cron Triggers allow users to map a cron expression to a Worker script
+ using a ScheduledEvent listener that enables Workers to be executed on a
+ schedule. Worker Cron Triggers are ideal for running periodic jobs for
+ maintenance or calling third-party APIs to collect up-to-date data.
+---
+
+# cloudflare_workers_cron_trigger (Resource)
+
+Worker Cron Triggers allow users to map a cron expression to a Worker script
+using a `ScheduledEvent` listener that enables Workers to be executed on a
+schedule. Worker Cron Triggers are ideal for running periodic jobs for
+maintenance or calling third-party APIs to collect up-to-date data.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_workers_script" "example_script" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example-script"
+ content = file("path/to/my.js")
+}
+
+resource "cloudflare_workers_cron_trigger" "example_trigger" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ script_name = cloudflare_workers_script.example_script.name
+ schedules = [
+ "*/5 * * * *", # every 5 minutes
+ "10 7 * * mon-fri", # 7:10am every weekday
+ ]
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `schedules` (Set of String) Cron expressions to execute the Worker script.
+- `script_name` (String) Worker script to target for the schedules.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_cron_trigger.example /
+```
diff --git a/docs/resources/workers_domain.md b/docs/resources/workers_domain.md
new file mode 100644
index 0000000000..e6794540c2
--- /dev/null
+++ b/docs/resources/workers_domain.md
@@ -0,0 +1,46 @@
+---
+page_title: "cloudflare_workers_domain Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Creates a Worker Custom Domain.
+---
+
+# cloudflare_workers_domain (Resource)
+
+Creates a Worker Custom Domain.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_workers_domain" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ hostname = "subdomain.example.com"
+ service = "my-service"
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `hostname` (String) Hostname of the Worker Domain.
+- `service` (String) Name of worker script to attach the domain to.
+- `zone_id` (String) The zone identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `environment` (String) The name of the Worker environment. Defaults to `production`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_domain.example /
+```
diff --git a/docs/resources/workers_for_platforms_dispatch_namespace.md b/docs/resources/workers_for_platforms_dispatch_namespace.md
new file mode 100644
index 0000000000..1ba954b879
--- /dev/null
+++ b/docs/resources/workers_for_platforms_dispatch_namespace.md
@@ -0,0 +1,48 @@
+---
+page_title: "cloudflare_workers_for_platforms_dispatch_namespace Resource - Cloudflare"
+subcategory: ""
+description: |-
+ The Workers for Platforms https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/ resource allows you
+ to manage Cloudflare Workers for Platforms dispatch namespaces.
+---
+
+# cloudflare_workers_for_platforms_dispatch_namespace (Resource)
+
+The [Workers for Platforms](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/) resource allows you
+to manage Cloudflare Workers for Platforms dispatch namespaces.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_workers_for_platforms_dispatch_namespace" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example-namespace"
+}
+
+resource "cloudflare_workers_script" "customer_worker_1" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "customer-worker-1"
+ content = file("script.js")
+ dispatch_namespace = cloudflare_workers_for_platforms_dispatch_namespace.example.name
+ tags = ["free"]
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) The name of the Workers for Platforms namespace.
+
+### Read-Only
+
+- `id` (String) The identifier of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_for_platforms_dispatch_namespace.example /
+```
diff --git a/docs/resources/workers_for_platforms_namespace.md b/docs/resources/workers_for_platforms_namespace.md
index f94e61ad59..61d76a5788 100644
--- a/docs/resources/workers_for_platforms_namespace.md
+++ b/docs/resources/workers_for_platforms_namespace.md
@@ -19,7 +19,7 @@ resource "cloudflare_workers_for_platforms_namespace" "example" {
name = "example-namespace"
}
-resource "cloudflare_worker_script" "customer_worker_1" {
+resource "cloudflare_workers_script" "customer_worker_1" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "customer-worker-1"
content = file("script.js")
diff --git a/docs/resources/workers_route.md b/docs/resources/workers_route.md
new file mode 100644
index 0000000000..bf3cb5efd1
--- /dev/null
+++ b/docs/resources/workers_route.md
@@ -0,0 +1,48 @@
+---
+page_title: "cloudflare_workers_route Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare worker route resource. A route will also require a cloudflare_worker_script.
+---
+
+# cloudflare_workers_route (Resource)
+
+Provides a Cloudflare worker route resource. A route will also require a `cloudflare_worker_script`.
+
+## Example Usage
+
+```terraform
+# Runs the specified worker script for all URLs that match `example.com/*`
+resource "cloudflare_workers_route" "my_route" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ pattern = "example.com/*"
+ script_name = cloudflare_workers_script.my_script.name
+}
+
+resource "cloudflare_workers_script" "my_script" {
+ # see "cloudflare_workers_script" documentation ...
+}
+```
+
+## Schema
+
+### Required
+
+- `pattern` (String) The [route pattern](https://developers.cloudflare.com/workers/about/routes/) to associate the Worker with.
+- `zone_id` (String) The zone identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `script_name` (String) Worker script name to invoke for requests that match the route pattern.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_route.example /
+```
diff --git a/docs/resources/workers_script.md b/docs/resources/workers_script.md
new file mode 100644
index 0000000000..236c7887f4
--- /dev/null
+++ b/docs/resources/workers_script.md
@@ -0,0 +1,193 @@
+---
+page_title: "cloudflare_workers_script Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare worker script resource. In order for a script to be active, you'll also need to setup a cloudflare_worker_route.
+---
+
+# cloudflare_workers_script (Resource)
+
+Provides a Cloudflare worker script resource. In order for a script to be active, you'll also need to setup a `cloudflare_worker_route`.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_workers_kv_namespace" "my_namespace" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ title = "example"
+}
+
+# Sets the script with the name "script_1"
+resource "cloudflare_workers_script" "my_script" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "script_1"
+ content = file("script.js")
+
+ kv_namespace_binding {
+ name = "MY_EXAMPLE_KV_NAMESPACE"
+ namespace_id = cloudflare_workers_kv_namespace.my_namespace.id
+ }
+
+ plain_text_binding {
+ name = "MY_EXAMPLE_PLAIN_TEXT"
+ text = "foobar"
+ }
+
+ secret_text_binding {
+ name = "MY_EXAMPLE_SECRET_TEXT"
+ text = var.secret_foo_value
+ }
+
+ webassembly_binding {
+ name = "MY_EXAMPLE_WASM"
+ module = filebase64("example.wasm")
+ }
+
+ service_binding {
+ name = "MY_SERVICE_BINDING"
+ service = "MY_SERVICE"
+ environment = "production"
+ }
+
+ r2_bucket_binding {
+ name = "MY_BUCKET"
+ bucket_name = "MY_BUCKET_NAME"
+ }
+
+ analytics_engine_binding {
+ name = "MY_DATASET"
+ dataset = "dataset1"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `content` (String) The script content.
+- `name` (String) The name for the script. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `analytics_engine_binding` (Block Set) (see [below for nested schema](#nestedblock--analytics_engine_binding))
+- `compatibility_date` (String) The date to use for the compatibility flag.
+- `compatibility_flags` (Set of String) Compatibility flags used for Worker Scripts.
+- `d1_database_binding` (Block Set) (see [below for nested schema](#nestedblock--d1_database_binding))
+- `dispatch_namespace` (String) Name of the Workers for Platforms dispatch namespace.
+- `kv_namespace_binding` (Block Set) (see [below for nested schema](#nestedblock--kv_namespace_binding))
+- `logpush` (Boolean) Enabling allows Worker events to be sent to a defined Logpush destination.
+- `module` (Boolean) Whether to upload Worker as a module.
+- `placement` (Block Set) (see [below for nested schema](#nestedblock--placement))
+- `plain_text_binding` (Block Set) (see [below for nested schema](#nestedblock--plain_text_binding))
+- `queue_binding` (Block Set) (see [below for nested schema](#nestedblock--queue_binding))
+- `r2_bucket_binding` (Block Set) (see [below for nested schema](#nestedblock--r2_bucket_binding))
+- `secret_text_binding` (Block Set) (see [below for nested schema](#nestedblock--secret_text_binding))
+- `service_binding` (Block Set) (see [below for nested schema](#nestedblock--service_binding))
+- `tags` (Set of String)
+- `webassembly_binding` (Block Set) (see [below for nested schema](#nestedblock--webassembly_binding))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `analytics_engine_binding`
+
+Required:
+
+- `dataset` (String) The name of the Analytics Engine dataset to write to.
+- `name` (String) The global variable for the binding in your Worker code.
+
+
+
+### Nested Schema for `d1_database_binding`
+
+Required:
+
+- `database_id` (String) Database ID of D1 database to use.
+- `name` (String) The global variable for the binding in your Worker code.
+
+
+
+### Nested Schema for `kv_namespace_binding`
+
+Required:
+
+- `name` (String) The global variable for the binding in your Worker code.
+- `namespace_id` (String) ID of the KV namespace you want to use.
+
+
+
+### Nested Schema for `placement`
+
+Required:
+
+- `mode` (String) The placement mode for the Worker. Available values: `smart`.
+
+
+
+### Nested Schema for `plain_text_binding`
+
+Required:
+
+- `name` (String) The global variable for the binding in your Worker code.
+- `text` (String) The plain text you want to store.
+
+
+
+### Nested Schema for `queue_binding`
+
+Required:
+
+- `binding` (String) The name of the global variable for the binding in your Worker code.
+- `queue` (String) Name of the queue you want to use.
+
+
+
+### Nested Schema for `r2_bucket_binding`
+
+Required:
+
+- `bucket_name` (String) The name of the Bucket to bind to.
+- `name` (String) The global variable for the binding in your Worker code.
+
+
+
+### Nested Schema for `secret_text_binding`
+
+Required:
+
+- `name` (String) The global variable for the binding in your Worker code.
+- `text` (String, Sensitive) The secret text you want to store.
+
+
+
+### Nested Schema for `service_binding`
+
+Required:
+
+- `name` (String) The global variable for the binding in your Worker code.
+- `service` (String) The name of the Worker to bind to.
+
+Optional:
+
+- `environment` (String) The name of the Worker environment to bind to.
+
+
+
+### Nested Schema for `webassembly_binding`
+
+Required:
+
+- `module` (String) The base64 encoded wasm module you want to store.
+- `name` (String) The global variable for the binding in your Worker code.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_script.example /
+```
diff --git a/docs/resources/workers_secret.md b/docs/resources/workers_secret.md
new file mode 100644
index 0000000000..a03fca73df
--- /dev/null
+++ b/docs/resources/workers_secret.md
@@ -0,0 +1,42 @@
+---
+page_title: "cloudflare_workers_secret Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Worker secret resource.
+---
+
+# cloudflare_workers_secret (Resource)
+
+Provides a Cloudflare Worker secret resource.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_workers_secret" "my_secret" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "MY_EXAMPLE_SECRET_TEXT"
+ script_name = "script_1"
+ secret_text = "my_secret_value"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) The name of the Worker secret. **Modifying this attribute will force creation of a new resource.**
+- `script_name` (String) The name of the Worker script to associate the secret with. **Modifying this attribute will force creation of a new resource.**
+- `secret_text` (String, Sensitive) The text of the Worker secret. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_workers_secret.example //
+```
diff --git a/docs/resources/zero_trust_access_application.md b/docs/resources/zero_trust_access_application.md
new file mode 100644
index 0000000000..e2db34220d
--- /dev/null
+++ b/docs/resources/zero_trust_access_application.md
@@ -0,0 +1,303 @@
+---
+page_title: "cloudflare_zero_trust_access_application Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Application resource. Access
+ Applications are used to restrict access to a whole application using an
+ authorisation gateway managed by Cloudflare.
+---
+
+# cloudflare_zero_trust_access_application (Resource)
+
+Provides a Cloudflare Access Application resource. Access
+Applications are used to restrict access to a whole application using an
+authorisation gateway managed by Cloudflare.
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_access_application" "staging_app" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "staging application"
+ domain = "staging.example.com"
+ type = "self_hosted"
+ session_duration = "24h"
+ auto_redirect_to_identity = false
+ policies = [
+ cloudflare_access_policy.example_1.id,
+ cloudflare_access_policy.example_2.id
+ ]
+}
+
+# With CORS configuration
+resource "cloudflare_zero_trust_access_application" "staging_app" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "staging application"
+ domain = "staging.example.com"
+ type = "self_hosted"
+ session_duration = "24h"
+ policies = [
+ cloudflare_access_policy.example_1.id,
+ cloudflare_access_policy.example_2.id
+ ]
+ cors_headers {
+ allowed_methods = ["GET", "POST", "OPTIONS"]
+ allowed_origins = ["https://example.com"]
+ allow_credentials = true
+ max_age = 10
+ }
+}
+```
+
+## Schema
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`.
+- `allow_authenticate_via_warp` (Boolean) When set to true, users can authenticate to this application using their WARP session. When set to false this application will always require direct IdP authentication. This setting always overrides the organization setting for WARP authentication.
+- `allowed_idps` (Set of String) The identity providers selected for the application.
+- `app_launcher_logo_url` (String) The logo URL of the app launcher.
+- `app_launcher_visible` (Boolean) Option to show/hide applications in App Launcher. Defaults to `true`.
+- `auto_redirect_to_identity` (Boolean) Option to skip identity provider selection if only one is configured in `allowed_idps`. Defaults to `false`.
+- `bg_color` (String) The background color of the app launcher.
+- `cors_headers` (Block List) CORS configuration for the Access Application. See below for reference structure. (see [below for nested schema](#nestedblock--cors_headers))
+- `custom_deny_message` (String) Option that returns a custom error message when a user is denied access to the application.
+- `custom_deny_url` (String) Option that redirects to a custom URL when a user is denied access to the application via identity based rules.
+- `custom_non_identity_deny_url` (String) Option that redirects to a custom URL when a user is denied access to the application via non identity rules.
+- `custom_pages` (Set of String) The custom pages selected for the application.
+- `domain` (String) The primary hostname and path that Access will secure. If the app is visible in the App Launcher dashboard, this is the domain that will be displayed.
+- `enable_binding_cookie` (Boolean) Option to provide increased security against compromised authorization tokens and CSRF attacks by requiring an additional "binding" cookie on requests. Defaults to `false`.
+- `footer_links` (Block Set) The footer links of the app launcher. (see [below for nested schema](#nestedblock--footer_links))
+- `header_bg_color` (String) The background color of the header bar in the app launcher.
+- `http_only_cookie_attribute` (Boolean) Option to add the `HttpOnly` cookie flag to access tokens.
+- `landing_page_design` (Block List, Max: 1) The landing page design of the app launcher. (see [below for nested schema](#nestedblock--landing_page_design))
+- `logo_url` (String) Image URL for the logo shown in the app launcher dashboard.
+- `name` (String) Friendly name of the Access Application.
+- `options_preflight_bypass` (Boolean) Allows options preflight requests to bypass Access authentication and go directly to the origin. Cannot turn on if cors_headers is set. Defaults to `false`.
+- `policies` (List of String) The policies associated with the application, in ascending order of precedence. Warning: Do not use this field while you still have this application ID referenced as `application_id` in any `cloudflare_access_policy` resource, as it can result in an inconsistent state.
+- `saas_app` (Block List, Max: 1) SaaS configuration for the Access Application. (see [below for nested schema](#nestedblock--saas_app))
+- `same_site_cookie_attribute` (String) Defines the same-site cookie setting for access tokens. Available values: `none`, `lax`, `strict`.
+- `scim_config` (Block List, Max: 1) Configuration for provisioning to this application via SCIM. This is currently in closed beta. (see [below for nested schema](#nestedblock--scim_config))
+- `self_hosted_domains` (Set of String) List of domains that access will secure. Only present for self_hosted, vnc, and ssh applications. Always includes the value set as `domain`.
+- `service_auth_401_redirect` (Boolean) Option to return a 401 status code in service authentication rules on failed requests. Defaults to `false`.
+- `session_duration` (String) How often a user will be forced to re-authorise. Must be in the format `48h` or `2h45m`. Defaults to `24h`.
+- `skip_app_launcher_login_page` (Boolean) Option to skip the App Launcher landing page. Defaults to `false`.
+- `skip_interstitial` (Boolean) Option to skip the authorization interstitial when using the CLI. Defaults to `false`.
+- `tags` (Set of String) The itags associated with the application.
+- `type` (String) The application type. Available values: `app_launcher`, `bookmark`, `biso`, `dash_sso`, `saas`, `self_hosted`, `ssh`, `vnc`, `warp`. Defaults to `self_hosted`.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `aud` (String) Application Audience (AUD) Tag of the application.
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `cors_headers`
+
+Optional:
+
+- `allow_all_headers` (Boolean) Value to determine whether all HTTP headers are exposed.
+- `allow_all_methods` (Boolean) Value to determine whether all methods are exposed.
+- `allow_all_origins` (Boolean) Value to determine whether all origins are permitted to make CORS requests.
+- `allow_credentials` (Boolean) Value to determine if credentials (cookies, authorization headers, or TLS client certificates) are included with requests.
+- `allowed_headers` (Set of String) List of HTTP headers to expose via CORS.
+- `allowed_methods` (Set of String) List of methods to expose via CORS.
+- `allowed_origins` (Set of String) List of origins permitted to make CORS requests.
+- `max_age` (Number) The maximum time a preflight request will be cached.
+
+
+
+### Nested Schema for `footer_links`
+
+Optional:
+
+- `name` (String) The name of the footer link.
+- `url` (String) The URL of the footer link.
+
+
+
+### Nested Schema for `landing_page_design`
+
+Optional:
+
+- `button_color` (String) The button color of the landing page.
+- `button_text_color` (String) The button text color of the landing page.
+- `image_url` (String) The URL of the image to be displayed in the landing page.
+- `message` (String) The message of the landing page.
+- `title` (String) The title of the landing page.
+
+
+
+### Nested Schema for `saas_app`
+
+Optional:
+
+- `access_token_lifetime` (String) The lifetime of the Access Token after creation. Valid units are `m` and `h`. Must be greater than or equal to 1m and less than or equal to 24h.
+- `allow_pkce_without_client_secret` (Boolean) Allow PKCE flow without a client secret.
+- `app_launcher_url` (String) The URL where this applications tile redirects users.
+- `auth_type` (String) **Modifying this attribute will force creation of a new resource.**
+- `consumer_service_url` (String) The service provider's endpoint that is responsible for receiving and parsing a SAML assertion.
+- `custom_attribute` (Block List) Custom attribute mapped from IDPs. (see [below for nested schema](#nestedblock--saas_app--custom_attribute))
+- `custom_claim` (Block List) Custom claim mapped from IDPs. (see [below for nested schema](#nestedblock--saas_app--custom_claim))
+- `default_relay_state` (String) The relay state used if not provided by the identity provider.
+- `grant_types` (Set of String) The OIDC flows supported by this application.
+- `group_filter_regex` (String) A regex to filter Cloudflare groups returned in ID token and userinfo endpoint.
+- `hybrid_and_implicit_options` (Block List, Max: 1) Hybrid and Implicit Flow options. (see [below for nested schema](#nestedblock--saas_app--hybrid_and_implicit_options))
+- `name_id_format` (String) The format of the name identifier sent to the SaaS application.
+- `name_id_transform_jsonata` (String) A [JSONata](https://jsonata.org/) expression that transforms an application's user identities into a NameID value for its SAML assertion. This expression should evaluate to a singular string. The output of this expression can override the `name_id_format` setting.
+- `redirect_uris` (Set of String) The permitted URL's for Cloudflare to return Authorization codes and Access/ID tokens.
+- `refresh_token_options` (Block List) Refresh token grant options. (see [below for nested schema](#nestedblock--saas_app--refresh_token_options))
+- `saml_attribute_transform_jsonata` (String) A [JSONata](https://jsonata.org/) expression that transforms an application's user identities into attribute assertions in the SAML response. The expression can transform id, email, name, and groups values. It can also transform fields listed in the saml_attributes or oidc_fields of the identity provider used to authenticate. The output of this expression must be a JSON object.
+- `scopes` (Set of String) Define the user information shared with access.
+- `sp_entity_id` (String) A globally unique name for an identity or service provider.
+
+Read-Only:
+
+- `client_id` (String) The application client id.
+- `client_secret` (String, Sensitive) The application client secret, only returned on initial apply.
+- `idp_entity_id` (String) The unique identifier for the SaaS application.
+- `public_key` (String) The public certificate that will be used to verify identities.
+- `sso_endpoint` (String) The endpoint where the SaaS application will send login requests.
+
+
+### Nested Schema for `saas_app.custom_attribute`
+
+Required:
+
+- `source` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--saas_app--custom_attribute--source))
+
+Optional:
+
+- `friendly_name` (String) A friendly name for the attribute as provided to the SaaS app.
+- `name` (String) The name of the attribute as provided to the SaaS app.
+- `name_format` (String) A globally unique name for an identity or service provider.
+- `required` (Boolean) True if the attribute must be always present.
+
+
+### Nested Schema for `saas_app.custom_attribute.source`
+
+Required:
+
+- `name` (String) The name of the attribute as provided by the IDP.
+
+Optional:
+
+- `name_by_idp` (Map of String) A mapping from IdP ID to claim name.
+
+
+
+
+### Nested Schema for `saas_app.custom_claim`
+
+Required:
+
+- `source` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--saas_app--custom_claim--source))
+
+Optional:
+
+- `name` (String) The name of the attribute as provided to the SaaS app.
+- `required` (Boolean) True if the attribute must be always present.
+- `scope` (String) The scope of the claim.
+
+
+### Nested Schema for `saas_app.custom_claim.source`
+
+Required:
+
+- `name` (String) The name of the attribute as provided by the IDP.
+
+Optional:
+
+- `name_by_idp` (Map of String) A mapping from IdP ID to claim name.
+
+
+
+
+### Nested Schema for `saas_app.hybrid_and_implicit_options`
+
+Optional:
+
+- `return_access_token_from_authorization_endpoint` (Boolean) If true, the authorization endpoint will return an access token.
+- `return_id_token_from_authorization_endpoint` (Boolean) If true, the authorization endpoint will return an id token.
+
+
+
+### Nested Schema for `saas_app.refresh_token_options`
+
+Optional:
+
+- `lifetime` (String) How long a refresh token will be valid for after creation. Valid units are `m`, `h` and `d`. Must be longer than 1m.
+
+
+
+
+### Nested Schema for `scim_config`
+
+Required:
+
+- `idp_uid` (String) The UID of the IdP to use as the source for SCIM resources to provision to this application.
+- `remote_uri` (String) The base URI for the application's SCIM-compatible API.
+
+Optional:
+
+- `authentication` (Block List, Max: 1) Attributes for configuring HTTP Basic, OAuth Bearer token, or OAuth 2 authentication schemes for SCIM provisioning to an application. (see [below for nested schema](#nestedblock--scim_config--authentication))
+- `deactivate_on_delete` (Boolean) If false, propagates DELETE requests to the target application for SCIM resources. If true, sets 'active' to false on the SCIM resource. Note: Some targets do not support DELETE operations.
+- `enabled` (Boolean) Whether SCIM provisioning is turned on for this application.
+- `mappings` (Block List) A list of mappings to apply to SCIM resources before provisioning them in this application. These can transform or filter the resources to be provisioned. (see [below for nested schema](#nestedblock--scim_config--mappings))
+
+
+### Nested Schema for `scim_config.authentication`
+
+Required:
+
+- `scheme` (String) The authentication scheme to use when making SCIM requests to this application.
+
+Optional:
+
+- `authorization_url` (String) URL used to generate the auth code used during token generation. Required when using `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.client_id`, `scim_config.0.authentication.0.token_url`. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.token`.
+- `client_id` (String) Client ID used to authenticate when generating a token for authenticating with the remote SCIM service. Required when using `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.token_url`. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.token`.
+- `client_secret` (String) Secret used to authenticate when generating a token for authenticating with the remove SCIM service. Required when using `scim_config.0.authentication.0.client_id`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.token_url`. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.token`.
+- `password` (String) Required when using `scim_config.0.authentication.0.user`. Conflicts with `scim_config.0.authentication.0.token`, `scim_config.0.authentication.0.client_id`, `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.token_url`, `scim_config.0.authentication.0.scopes`.
+- `scopes` (Set of String) The authorization scopes to request when generating the token used to authenticate with the remove SCIM service. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.token`.
+- `token` (String) Token used to authenticate with the remote SCIM service. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.client_id`, `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.token_url`, `scim_config.0.authentication.0.scopes`.
+- `token_url` (String) URL used to generate the token used to authenticate with the remote SCIM service. Required when using `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.client_id`. Conflicts with `scim_config.0.authentication.0.user`, `scim_config.0.authentication.0.password`, `scim_config.0.authentication.0.token`.
+- `user` (String) User name used to authenticate with the remote SCIM service. Required when using `scim_config.0.authentication.0.password`. Conflicts with `scim_config.0.authentication.0.token`, `scim_config.0.authentication.0.client_id`, `scim_config.0.authentication.0.client_secret`, `scim_config.0.authentication.0.authorization_url`, `scim_config.0.authentication.0.token_url`, `scim_config.0.authentication.0.scopes`.
+
+
+
+### Nested Schema for `scim_config.mappings`
+
+Required:
+
+- `schema` (String) Which SCIM resource type this mapping applies to.
+
+Optional:
+
+- `enabled` (Boolean) Whether or not this mapping is enabled.
+- `filter` (String) A [SCIM filter expression](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.2) that matches resources that should be provisioned to this application.
+- `operations` (Block List, Max: 1) Whether or not this mapping applies to creates, updates, or deletes. (see [below for nested schema](#nestedblock--scim_config--mappings--operations))
+- `transform_jsonata` (String) A [JSONata](https://jsonata.org/) expression that transforms the resource before provisioning it in the application.
+
+
+### Nested Schema for `scim_config.mappings.operations`
+
+Optional:
+
+- `create` (Boolean) Whether or not this mapping applies to create (POST) operations.
+- `delete` (Boolean) Whether or not this mapping applies to DELETE operations.
+- `update` (Boolean) Whether or not this mapping applies to update (PATCH/PUT) operations.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_access_application.example /
+```
diff --git a/docs/resources/zero_trust_access_custom_page.md b/docs/resources/zero_trust_access_custom_page.md
new file mode 100644
index 0000000000..2637cf94f4
--- /dev/null
+++ b/docs/resources/zero_trust_access_custom_page.md
@@ -0,0 +1,43 @@
+---
+page_title: "cloudflare_zero_trust_access_custom_page Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource to customize the pages your end users will see
+ when trying to reach applications behind Cloudflare Access.
+---
+
+# cloudflare_zero_trust_access_custom_page (Resource)
+
+Provides a resource to customize the pages your end users will see
+when trying to reach applications behind Cloudflare Access.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_access_custom_page" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "example"
+ type = "forbidden"
+ custom_html = "Forbidden
"
+}
+```
+
+## Schema
+
+### Required
+
+- `name` (String) Friendly name of the Access Custom Page configuration.
+- `type` (String) Type of Access custom page to create. Available values: `identity_denied`, `forbidden`.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
+- `app_count` (Number) Number of apps to display on the custom page.
+- `custom_html` (String) Custom HTML to display on the custom page.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/zero_trust_access_group.md b/docs/resources/zero_trust_access_group.md
new file mode 100644
index 0000000000..b05f84fd37
--- /dev/null
+++ b/docs/resources/zero_trust_access_group.md
@@ -0,0 +1,374 @@
+---
+page_title: "cloudflare_zero_trust_access_group Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Group resource. Access Groups are used
+ in conjunction with Access Policies to restrict access to a
+ particular resource based on group membership.
+---
+
+# cloudflare_zero_trust_access_group (Resource)
+
+Provides a Cloudflare Access Group resource. Access Groups are used
+in conjunction with Access Policies to restrict access to a
+particular resource based on group membership.
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+## Example Usage
+
+```terraform
+# Allowing access to `test@example.com` email address only
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging group"
+
+ include {
+ email = ["test@example.com"]
+ }
+}
+
+# Allowing `test@example.com` to access but only when coming from a
+# specific IP.
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging group"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ ip = [var.office_ip]
+ }
+}
+
+# Allow members of an Azure Group. The ID is the group UUID (id) in Azure.
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "test_group"
+
+ include {
+ azure {
+ identity_provider_id = "ca298b82-93b5-41bf-bc2d-10493f09b761"
+ id = ["86773093-5feb-48dd-814b-7ccd3676ff50"]
+ }
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `include` (Block List, Min: 1) (see [below for nested schema](#nestedblock--include))
+- `name` (String)
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
+- `exclude` (Block List) (see [below for nested schema](#nestedblock--exclude))
+- `require` (Block List) (see [below for nested schema](#nestedblock--require))
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `include`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--include--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--include--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--include--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--include--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--include--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--include--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--include--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `include.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `include.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `include.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `include.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `include.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `include.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `include.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+
+
+
+### Nested Schema for `exclude`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--exclude--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--exclude--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--exclude--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--exclude--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--exclude--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--exclude--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--exclude--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `exclude.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `exclude.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `exclude.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `exclude.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `exclude.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `exclude.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `exclude.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+
+
+
+### Nested Schema for `require`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--require--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--require--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--require--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--require--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--require--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--require--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--require--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `require.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `require.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `require.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `require.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `require.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `require.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `require.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_access_group.example /
+```
diff --git a/docs/resources/zero_trust_access_identity_provider.md b/docs/resources/zero_trust_access_identity_provider.md
new file mode 100644
index 0000000000..f471f70bd1
--- /dev/null
+++ b/docs/resources/zero_trust_access_identity_provider.md
@@ -0,0 +1,143 @@
+---
+page_title: "cloudflare_zero_trust_access_identity_provider Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Identity Provider resource. Identity
+ Providers are used as an authentication or authorisation source
+ within Access.
+---
+
+# cloudflare_zero_trust_access_identity_provider (Resource)
+
+Provides a Cloudflare Access Identity Provider resource. Identity
+Providers are used as an authentication or authorisation source
+within Access.
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+## Example Usage
+
+```terraform
+# one time pin
+resource "cloudflare_zero_trust_access_identity_provider" "pin_login" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "PIN login"
+ type = "onetimepin"
+}
+
+# oauth
+resource "cloudflare_zero_trust_access_identity_provider" "github_oauth" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GitHub OAuth"
+ type = "github"
+ config {
+ client_id = "example"
+ client_secret = "secret_key"
+ }
+}
+
+# saml
+resource "cloudflare_zero_trust_access_identity_provider" "jumpcloud_saml" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "JumpCloud SAML"
+ type = "saml"
+ config {
+ issuer_url = "jumpcloud"
+ sso_target_url = "https://sso.myexample.jumpcloud.com/saml2/cloudflareaccess"
+ attributes = ["email", "username"]
+ sign_request = false
+ idp_public_cert = "MIIDpDCCAoygAwIBAgIGAV2ka+55MA0GCSqGSIb3DQEBCwUAMIGSMQswCQ...GF/Q2/MHadws97cZg\nuTnQyuOqPuHbnN83d/2l1NSYKCbHt24o"
+ }
+}
+
+# okta
+resource "cloudflare_zero_trust_access_identity_provider" "okta" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Okta"
+ type = "okta"
+ config {
+ client_id = "example"
+ client_secret = "secret_key"
+ api_token = "okta_api_token"
+ okta_account = "https://example.com"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `name` (String) Friendly name of the Access Identity Provider configuration.
+- `type` (String) The provider type to use. Available values: `azureAD`, `centrify`, `facebook`, `github`, `google`, `google-apps`, `linkedin`, `oidc`, `okta`, `onelogin`, `onetimepin`, `pingone`, `saml`, `yandex`.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
+- `config` (Block List) Provider configuration from the [developer documentation](https://developers.cloudflare.com/access/configuring-identity-providers/). (see [below for nested schema](#nestedblock--config))
+- `scim_config` (Block List) Configuration for SCIM settings for a given IDP. (see [below for nested schema](#nestedblock--scim_config))
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `config`
+
+Optional:
+
+- `api_token` (String)
+- `apps_domain` (String)
+- `attributes` (List of String)
+- `auth_url` (String)
+- `authorization_server_id` (String)
+- `centrify_account` (String)
+- `centrify_app_id` (String)
+- `certs_url` (String)
+- `claims` (List of String)
+- `client_id` (String)
+- `client_secret` (String)
+- `conditional_access_enabled` (Boolean)
+- `directory_id` (String)
+- `email_attribute_name` (String)
+- `email_claim_name` (String)
+- `idp_public_cert` (String)
+- `issuer_url` (String)
+- `okta_account` (String)
+- `onelogin_account` (String)
+- `ping_env_id` (String)
+- `pkce_enabled` (Boolean)
+- `scopes` (List of String)
+- `sign_request` (Boolean)
+- `sso_target_url` (String)
+- `support_groups` (Boolean)
+- `token_url` (String)
+
+Read-Only:
+
+- `redirect_url` (String)
+
+
+
+### Nested Schema for `scim_config`
+
+Optional:
+
+- `enabled` (Boolean)
+- `group_member_deprovision` (Boolean)
+- `seat_deprovision` (Boolean)
+- `secret` (String, Sensitive)
+- `user_deprovision` (Boolean)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_access_identity_provider.example /
+```
diff --git a/docs/resources/zero_trust_access_mtls_certificate.md b/docs/resources/zero_trust_access_mtls_certificate.md
new file mode 100644
index 0000000000..e909774c10
--- /dev/null
+++ b/docs/resources/zero_trust_access_mtls_certificate.md
@@ -0,0 +1,65 @@
+---
+page_title: "cloudflare_zero_trust_access_mtls_certificate Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Mutual TLS Certificate resource.
+ Mutual TLS authentication ensures that the traffic is secure and
+ trusted in both directions between a client and server and can be
+ used with Access to only allows requests from devices with a
+ corresponding client certificate.
+---
+
+# cloudflare_zero_trust_access_mtls_certificate (Resource)
+
+Provides a Cloudflare Access Mutual TLS Certificate resource.
+Mutual TLS authentication ensures that the traffic is secure and
+trusted in both directions between a client and server and can be
+ used with Access to only allows requests from devices with a
+ corresponding client certificate.
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_access_mtls_certificate" "my_cert" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "My Root Cert"
+ certificate = var.ca_pem
+ associated_hostnames = ["staging.example.com"]
+}
+```
+
+## Schema
+
+### Required
+
+- `name` (String) The name of the certificate.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`.
+- `associated_hostnames` (List of String) The hostnames that will be prompted for this certificate.
+- `certificate` (String) The Root CA for your certificates.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `fingerprint` (String)
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Account level import.
+$ terraform import cloudflare_zero_sd -t_access_mtls_certificate.example account//
+
+# Zone level import.
+$ terraform import cloudflare_zero_sd -t_access_mtls_certificate.example zone//
+```
diff --git a/docs/resources/zero_trust_access_mtls_hostname_settings.md b/docs/resources/zero_trust_access_mtls_hostname_settings.md
new file mode 100644
index 0000000000..f7749dbb21
--- /dev/null
+++ b/docs/resources/zero_trust_access_mtls_hostname_settings.md
@@ -0,0 +1,55 @@
+---
+page_title: "cloudflare_zero_trust_access_mtls_hostname_settings Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Mutual TLS Certificate Settings resource.
+---
+
+# cloudflare_zero_trust_access_mtls_hostname_settings (Resource)
+
+Provides a Cloudflare Access Mutual TLS Certificate Settings resource.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_access_mtls_hostname_settings" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ settings {
+ hostname = "example.com"
+ client_certificate_forwarding = true
+ china_network = false
+ }
+}
+```
+
+## Schema
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource.
+- `settings` (Block List) (see [below for nested schema](#nestedblock--settings))
+- `zone_id` (String) The zone identifier to target for the resource.
+
+
+### Nested Schema for `settings`
+
+Required:
+
+- `hostname` (String) The hostname that these settings apply to.
+
+Optional:
+
+- `china_network` (Boolean) Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled.
+- `client_certificate_forwarding` (Boolean) Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Account level mTLS hostname settings import.
+$ terraform import cloudflare_zero_trust_access_mtls_hostname_settings.example account/
+
+# Zone level mTLS hostname settings import.
+$ terraform import cloudflare_zero_trust_access_mtls_hostname_settings.example zone/
+```
diff --git a/docs/resources/zero_trust_access_organization.md b/docs/resources/zero_trust_access_organization.md
new file mode 100644
index 0000000000..16fa07b954
--- /dev/null
+++ b/docs/resources/zero_trust_access_organization.md
@@ -0,0 +1,59 @@
+---
+page_title: "cloudflare_zero_trust_access_organization Resource - Cloudflare"
+subcategory: ""
+description: |-
+ A Zero Trust organization defines the user login experience.
+---
+
+# cloudflare_zero_trust_access_organization (Resource)
+
+A Zero Trust organization defines the user login experience.
+
+
+
+## Schema
+
+### Required
+
+- `auth_domain` (String) The unique subdomain assigned to your Zero Trust organization.
+- `name` (String) The name of your Zero Trust organization.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`.
+- `allow_authenticate_via_warp` (Boolean) When set to true, users can authenticate via WARP for any application in your organization. Application settings will take precedence over this value.
+- `auto_redirect_to_identity` (Boolean) When set to true, users skip the identity provider selection step during login.
+- `custom_pages` (Block List) Custom pages for your Zero Trust organization. (see [below for nested schema](#nestedblock--custom_pages))
+- `is_ui_read_only` (Boolean) When set to true, this will disable all editing of Access resources via the Zero Trust Dashboard.
+- `login_design` (Block List) (see [below for nested schema](#nestedblock--login_design))
+- `session_duration` (String) How often a user will be forced to re-authorise. Must be in the format `48h` or `2h45m`.
+- `ui_read_only_toggle_reason` (String) A description of the reason why the UI read only field is being toggled.
+- `user_seat_expiration_inactive_time` (String) The amount of time a user seat is inactive before it expires. When the user seat exceeds the set time of inactivity, the user is removed as an active seat and no longer counts against your Teams seat count. Must be in the format `300ms` or `2h45m`.
+- `warp_auth_session_duration` (String) The amount of time that tokens issued for applications will be valid. Must be in the format 30m or 2h45m. Valid time units are: m, h.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `custom_pages`
+
+Optional:
+
+- `forbidden` (String) The id of the forbidden page.
+- `identity_denied` (String) The id of the identity denied page.
+
+
+
+### Nested Schema for `login_design`
+
+Optional:
+
+- `background_color` (String) The background color on the login page.
+- `footer_text` (String) The text at the bottom of the login page.
+- `header_text` (String) The text at the top of the login page.
+- `logo_path` (String) The URL of the logo on the login page.
+- `text_color` (String) The text color on the login page.
+
+
diff --git a/docs/resources/zero_trust_access_policy.md b/docs/resources/zero_trust_access_policy.md
new file mode 100644
index 0000000000..1b912338d7
--- /dev/null
+++ b/docs/resources/zero_trust_access_policy.md
@@ -0,0 +1,391 @@
+---
+page_title: "cloudflare_zero_trust_access_policy Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Access Policy resource. Access Policies are
+ used in conjunction with Access Applications to restrict access to
+ a particular resource.
+---
+
+# cloudflare_zero_trust_access_policy (Resource)
+
+Provides a Cloudflare Access Policy resource. Access Policies are
+used in conjunction with Access Applications to restrict access to
+a particular resource.
+
+~> It's required that an `account_id` or `zone_id` is provided and in most cases using either is fine.
+ However, if you're using a scoped access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com" zone needs to use the `zone_id` argument.
+ If 'application_id' is omitted, the policy created can be reused by multiple access applications.
+ Any cloudflare_access_application resource can reference reusable policies through its `policies` argument.
+ To destroy a reusable policy and remove it from all applications' policies lists on the same apply, preemptively set the
+ lifecycle option `create_before_destroy` to true on the 'cloudflare_access_policy' resource.
+
+## Example Usage
+
+```terraform
+# Allowing access to `test@example.com` email address only
+resource "cloudflare_zero_trust_access_policy" "test_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging policy"
+ decision = "allow"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ email = ["test@example.com"]
+ }
+}
+
+# Allowing `test@example.com` to access but only when coming from a
+# specific IP.
+resource "cloudflare_zero_trust_access_policy" "test_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging policy"
+ decision = "allow"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ ip = [var.office_ip]
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `decision` (String) Defines the action Access will take if the policy matches the user. Available values: `allow`, `deny`, `non_identity`, `bypass`.
+- `include` (Block List, Min: 1) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--include))
+- `name` (String) Friendly name of the Access Policy.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
+- `application_id` (String) The ID of the application the policy is associated with. Required when using `precedence`. **Modifying this attribute will force creation of a new resource.**
+- `approval_group` (Block List) (see [below for nested schema](#nestedblock--approval_group))
+- `approval_required` (Boolean)
+- `exclude` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--exclude))
+- `isolation_required` (Boolean) Require this application to be served in an isolated browser for users matching this policy.
+- `precedence` (Number) The unique precedence for policies on a single application. Required when using `application_id`.
+- `purpose_justification_prompt` (String) The prompt to display to the user for a justification for accessing the resource. Required when using `purpose_justification_required`.
+- `purpose_justification_required` (Boolean) Whether to prompt the user for a justification for accessing the resource.
+- `require` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--require))
+- `session_duration` (String) How often a user will be forced to re-authorise. Must be in the format `48h` or `2h45m`.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `include`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--include--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--include--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--include--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--include--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--include--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--include--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--include--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `include.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `include.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `include.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `include.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `include.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `include.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `include.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+
+
+
+### Nested Schema for `approval_group`
+
+Required:
+
+- `approvals_needed` (Number) Number of approvals needed.
+
+Optional:
+
+- `email_addresses` (List of String) List of emails to request approval from.
+- `email_list_uuid` (String)
+
+
+
+### Nested Schema for `exclude`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--exclude--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--exclude--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--exclude--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--exclude--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--exclude--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--exclude--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--exclude--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `exclude.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `exclude.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `exclude.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `exclude.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `exclude.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `exclude.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `exclude.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+
+
+
+### Nested Schema for `require`
+
+Optional:
+
+- `any_valid_service_token` (Boolean)
+- `auth_context` (Block List) (see [below for nested schema](#nestedblock--require--auth_context))
+- `auth_method` (String)
+- `azure` (Block List) (see [below for nested schema](#nestedblock--require--azure))
+- `certificate` (Boolean)
+- `common_name` (String)
+- `common_names` (List of String) Overflow field if you need to have multiple common_name rules in a single policy. Use in place of the singular common_name field.
+- `device_posture` (List of String)
+- `email` (List of String)
+- `email_domain` (List of String)
+- `email_list` (List of String)
+- `everyone` (Boolean)
+- `external_evaluation` (Block List) (see [below for nested schema](#nestedblock--require--external_evaluation))
+- `geo` (List of String)
+- `github` (Block List) (see [below for nested schema](#nestedblock--require--github))
+- `group` (List of String)
+- `gsuite` (Block List) (see [below for nested schema](#nestedblock--require--gsuite))
+- `ip` (List of String) An IPv4 or IPv6 CIDR block.
+- `ip_list` (List of String) The ID of an existing IP list to reference.
+- `login_method` (List of String)
+- `okta` (Block List) (see [below for nested schema](#nestedblock--require--okta))
+- `saml` (Block List) (see [below for nested schema](#nestedblock--require--saml))
+- `service_token` (List of String)
+
+
+### Nested Schema for `require.auth_context`
+
+Required:
+
+- `ac_id` (String) The ACID of the Authentication Context.
+- `id` (String) The ID of the Authentication Context.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `require.azure`
+
+Optional:
+
+- `id` (List of String) The ID of the Azure group or user.
+- `identity_provider_id` (String) The ID of the Azure Identity provider.
+
+
+
+### Nested Schema for `require.external_evaluation`
+
+Optional:
+
+- `evaluate_url` (String)
+- `keys_url` (String)
+
+
+
+### Nested Schema for `require.github`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (String)
+- `teams` (List of String)
+
+
+
+### Nested Schema for `require.gsuite`
+
+Optional:
+
+- `email` (List of String)
+- `identity_provider_id` (String)
+
+
+
+### Nested Schema for `require.okta`
+
+Optional:
+
+- `identity_provider_id` (String)
+- `name` (List of String)
+
+
+
+### Nested Schema for `require.saml`
+
+Optional:
+
+- `attribute_name` (String)
+- `attribute_value` (String)
+- `identity_provider_id` (String)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_access_policy.example account///
+```
diff --git a/docs/resources/zero_trust_access_service_token.md b/docs/resources/zero_trust_access_service_token.md
new file mode 100644
index 0000000000..54d447855f
--- /dev/null
+++ b/docs/resources/zero_trust_access_service_token.md
@@ -0,0 +1,68 @@
+---
+page_title: "cloudflare_zero_trust_access_service_token Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Access Service Tokens are used for service-to-service communication
+ when an application is behind Cloudflare Access.
+---
+
+# cloudflare_zero_trust_access_service_token (Resource)
+
+Access Service Tokens are used for service-to-service communication
+when an application is behind Cloudflare Access.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_access_service_token" "my_app" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "CI/CD app"
+}
+
+# Generate a service token that will renew if terraform is ran within 30 days of expiration
+resource "cloudflare_zero_trust_access_service_token" "my_app" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "CI/CD app renewed"
+
+ min_days_for_renewal = 30
+
+ # This flag is important to set if min_days_for_renewal is defined otherwise
+ # there will be a brief period where the service relying on that token
+ # will not have access due to the resource being deleted
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `name` (String) Friendly name of the token's intent.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`.
+- `duration` (String) Length of time the service token is valid for. Available values: `8760h`, `17520h`, `43800h`, `87600h`, `forever`.
+- `min_days_for_renewal` (Number) Refresh the token if terraform is run within the specified amount of days before expiration. Defaults to `0`.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `client_id` (String) Client ID associated with the Service Token. **Modifying this attribute will force creation of a new resource.**
+- `client_secret` (String, Sensitive) A secret for interacting with Access protocols. **Modifying this attribute will force creation of a new resource.**
+- `expires_at` (String) Date when the token expires.
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# If you are importing an Access Service Token you will not have the
+# client_secret available in the state for use. The client_secret is only
+# available once, at creation. In most cases, it is better to just create a new
+# resource should you need to reference it in other resources.
+$ terraform import cloudflare_zero_trust_access_service_token.example /
+```
diff --git a/docs/resources/zero_trust_access_short_lived_certificate.md b/docs/resources/zero_trust_access_short_lived_certificate.md
new file mode 100644
index 0000000000..9773f0fa77
--- /dev/null
+++ b/docs/resources/zero_trust_access_short_lived_certificate.md
@@ -0,0 +1,65 @@
+---
+page_title: "cloudflare_zero_trust_access_short_lived_certificate Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Cloudflare Access can replace traditional SSH key models with
+ short-lived certificates issued to your users based on the token
+ generated by their Access login.
+---
+
+# cloudflare_zero_trust_access_short_lived_certificate (Resource)
+
+Cloudflare Access can replace traditional SSH key models with
+short-lived certificates issued to your users based on the token
+generated by their Access login.
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+## Example Usage
+
+```terraform
+# account level
+resource "cloudflare_zero_trust_access_short_lived_certificate" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ application_id = "6cd6cea3-3ef2-4542-9aea-85a0bbcd5414"
+}
+
+# zone level
+resource "cloudflare_zero_trust_access_short_lived_certificate" "another_example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ application_id = "fe2be0ff-7f13-4350-8c8e-a9b9795fe3c2"
+}
+```
+
+## Schema
+
+### Required
+
+- `application_id` (String) The Access Application ID to associate with the CA certificate.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`.
+
+### Read-Only
+
+- `aud` (String) Application Audience (AUD) Tag of the CA certificate.
+- `id` (String) The ID of this resource.
+- `public_key` (String) Cryptographic public key of the generated CA certificate.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Account level CA certificate import.
+$ terraform import cloudflare_zero_trust_access_short_lived_certificate.example account//
+
+# Zone level CA certificate import.
+$ terraform import cloudflare_zero_trust_access_short_lived_certificate.example account//
+```
diff --git a/docs/resources/zero_trust_access_tag.md b/docs/resources/zero_trust_access_tag.md
new file mode 100644
index 0000000000..cd59d5db47
--- /dev/null
+++ b/docs/resources/zero_trust_access_tag.md
@@ -0,0 +1,32 @@
+---
+page_title: "cloudflare_zero_trust_access_tag Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource to customize the pages your end users will see
+ when trying to reach applications behind Cloudflare Access.
+---
+
+# cloudflare_zero_trust_access_tag (Resource)
+
+Provides a resource to customize the pages your end users will see
+when trying to reach applications behind Cloudflare Access.
+
+
+
+## Schema
+
+### Required
+
+- `name` (String) Friendly name of the Access Tag.
+
+### Optional
+
+- `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. **Modifying this attribute will force creation of a new resource.**
+- `app_count` (Number) Number of apps associated with the tag.
+- `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/zero_trust_device_certificates.md b/docs/resources/zero_trust_device_certificates.md
new file mode 100644
index 0000000000..a7c7565b45
--- /dev/null
+++ b/docs/resources/zero_trust_device_certificates.md
@@ -0,0 +1,42 @@
+---
+page_title: "cloudflare_zero_trust_device_certificates Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare device policy certificates resource. Device
+ policy certificate resources enable client device certificate
+ generation.
+---
+
+# cloudflare_zero_trust_device_certificates (Resource)
+
+Provides a Cloudflare device policy certificates resource. Device
+policy certificate resources enable client device certificate
+generation.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_device_certificates" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ enabled = true
+}
+```
+
+## Schema
+
+### Required
+
+- `enabled` (Boolean) `true` if certificate generation is enabled.
+- `zone_id` (String) The zone identifier to target for the resource.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_device_certificates.example
+```
diff --git a/docs/resources/zero_trust_device_managed_networks.md b/docs/resources/zero_trust_device_managed_networks.md
new file mode 100644
index 0000000000..393663f1f0
--- /dev/null
+++ b/docs/resources/zero_trust_device_managed_networks.md
@@ -0,0 +1,53 @@
+---
+page_title: "cloudflare_zero_trust_device_managed_networks Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.
+---
+
+# cloudflare_zero_trust_device_managed_networks (Resource)
+
+Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_device_managed_networks" "managed_networks" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "managed-network-1"
+ type = "tls"
+ config {
+ tls_sockaddr = "foobar:1234"
+ sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `config` (Block List, Min: 1, Max: 1) The configuration containing information for the WARP client to detect the managed network. (see [below for nested schema](#nestedblock--config))
+- `name` (String) The name of the Device Managed Network. Must be unique.
+- `type` (String) The type of Device Managed Network. Available values: `tls`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `config`
+
+Required:
+
+- `sha256` (String) The SHA-256 hash of the TLS certificate presented by the host found at tls_sockaddr. If absent, regular certificate verification (trusted roots, valid timestamp, etc) will be used to validate the certificate.
+- `tls_sockaddr` (String) A network address of the form "host:port" that the WARP client will use to detect the presence of a TLS host.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_device_managed_networks.example /
+```
diff --git a/docs/resources/zero_trust_device_posture_integration.md b/docs/resources/zero_trust_device_posture_integration.md
new file mode 100644
index 0000000000..e930109d5a
--- /dev/null
+++ b/docs/resources/zero_trust_device_posture_integration.md
@@ -0,0 +1,71 @@
+---
+page_title: "cloudflare_zero_trust_device_posture_integration Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Device Posture Integration resource. Device
+ posture integrations configure third-party data providers for device
+ posture rules.
+---
+
+# cloudflare_zero_trust_device_posture_integration (Resource)
+
+Provides a Cloudflare Device Posture Integration resource. Device
+posture integrations configure third-party data providers for device
+posture rules.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_device_posture_integration" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Device posture integration"
+ type = "workspace_one"
+ interval = "24h"
+ config {
+ api_url = "https://example.com/api"
+ auth_url = "https://example.com/connect/token"
+ client_id = "client-id"
+ client_secret = "client-secret"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) Name of the device posture integration.
+- `type` (String) The device posture integration type. Available values: `workspace_one`, `uptycs`, `crowdstrike_s2s`, `intune`, `kolide`, `sentinelone_s2s`, `tanium_s2s`.
+
+### Optional
+
+- `config` (Block List) The device posture integration's connection authorization parameters. (see [below for nested schema](#nestedblock--config))
+- `identifier` (String)
+- `interval` (String) Indicates the frequency with which to poll the third-party API. Must be in the format `1h` or `30m`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `config`
+
+Optional:
+
+- `access_client_id` (String, Sensitive) The Access client ID to be used as the `Cf-Access-Client-ID` header when making a request to the `api_url`.
+- `access_client_secret` (String, Sensitive) The Access client secret to be used as the `Cf-Access-Client-Secret` header when making a request to the `api_url`.
+- `api_url` (String) The third-party API's URL.
+- `auth_url` (String) The third-party authorization API URL.
+- `client_id` (String) The client identifier for authenticating API calls.
+- `client_key` (String, Sensitive) The client key for authenticating API calls.
+- `client_secret` (String, Sensitive) The client secret for authenticating API calls.
+- `customer_id` (String) The customer identifier for authenticating API calls.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_device_posture_integration.example /
+```
diff --git a/docs/resources/zero_trust_device_posture_rule.md b/docs/resources/zero_trust_device_posture_rule.md
new file mode 100644
index 0000000000..510d43a9ad
--- /dev/null
+++ b/docs/resources/zero_trust_device_posture_rule.md
@@ -0,0 +1,112 @@
+---
+page_title: "cloudflare_zero_trust_device_posture_rule Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Device Posture Rule resource. Device posture rules configure security policies for device posture checks.
+---
+
+# cloudflare_zero_trust_device_posture_rule (Resource)
+
+Provides a Cloudflare Device Posture Rule resource. Device posture rules configure security policies for device posture checks.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_device_posture_rule" "eaxmple" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Corporate devices posture rule"
+ type = "os_version"
+ description = "Device posture rule for corporate devices."
+ schedule = "24h"
+ expiration = "24h"
+
+ match {
+ platform = "linux"
+ }
+
+ input {
+ id = cloudflare_teams_list.corporate_devices.id
+ version = "1.0.0"
+ operator = "<"
+ os_distro_name = "ubuntu"
+ os_distro_revision = "1.0.0"
+ os_version_extra = "(a)"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `type` (String) The device posture rule type. Available values: `serial_number`, `file`, `application`, `gateway`, `warp`, `domain_joined`, `os_version`, `disk_encryption`, `firewall`, `client_certificate`, `workspace_one`, `unique_client_id`, `crowdstrike_s2s`, `sentinelone`, `kolide`, `tanium_s2s`, `intune`, `sentinelone_s2s`.
+
+### Optional
+
+- `description` (String)
+- `expiration` (String) Expire posture results after the specified amount of time. Must be in the format `1h` or `30m`. Valid units are `h` and `m`.
+- `input` (Block List) Required for all rule types except `warp`, `gateway`, and `tanium`. (see [below for nested schema](#nestedblock--input))
+- `match` (Block List) The conditions that the client must match to run the rule. (see [below for nested schema](#nestedblock--match))
+- `name` (String) Name of the device posture rule.
+- `schedule` (String) Tells the client when to run the device posture check. Must be in the format `1h` or `30m`. Valid units are `h` and `m`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `input`
+
+Optional:
+
+- `active_threats` (Number) The number of active threats from SentinelOne.
+- `certificate_id` (String) The UUID of a Cloudflare managed certificate.
+- `check_disks` (Set of String) Specific volume(s) to check for encryption.
+- `cn` (String) The common name for a certificate.
+- `compliance_status` (String) The workspace one or intune device compliance status. `compliant` and `noncompliant` are values supported by both providers. `unknown`, `conflict`, `error`, `ingraceperiod` values are only supported by intune. Available values: `compliant`, `noncompliant`, `unknown`, `conflict`, `error`, `ingraceperiod`.
+- `connection_id` (String) The workspace one or intune connection id.
+- `count_operator` (String) The count comparison operator for kolide. Available values: `>`, `>=`, `<`, `<=`, `==`.
+- `domain` (String) The domain that the client must join.
+- `eid_last_seen` (String) The time a device last seen in Tanium. Must be in the format `1h` or `30m`. Valid units are `d`, `h` and `m`
+- `enabled` (Boolean) True if the firewall must be enabled.
+- `exists` (Boolean) Checks if the file should exist.
+- `id` (String) The Teams List id. Required for `serial_number` and `unique_client_id` rule types.
+- `infected` (Boolean) True if SentinelOne device is infected.
+- `is_active` (Boolean) True if SentinelOne device is active.
+- `issue_count` (String) The number of issues for kolide.
+- `last_seen` (String) The duration of time that the host was last seen from Crowdstrike. Must be in the format `1h` or `30m`. Valid units are `d`, `h` and `m`.
+- `network_status` (String) The network status from SentinelOne. Available values: `connected`, `disconnected`, `disconnecting`, `connecting`.
+- `operator` (String) The version comparison operator. Available values: `>`, `>=`, `<`, `<=`, `==`.
+- `os` (String) OS signal score from Crowdstrike. Value must be between 1 and 100.
+- `os_distro_name` (String) The operating system excluding version information.
+- `os_distro_revision` (String) The operating system version excluding OS name information or release name.
+- `os_version_extra` (String) Extra version value following the operating system semantic version.
+- `overall` (String) Overall ZTA score from Crowdstrike. Value must be between 1 and 100.
+- `path` (String) The path to the file.
+- `require_all` (Boolean) True if all drives must be encrypted.
+- `risk_level` (String) The risk level from Tanium. Available values: `low`, `medium`, `high`, `critical`.
+- `running` (Boolean) Checks if the application should be running.
+- `sensor_config` (String) Sensor signal score from Crowdstrike. Value must be between 1 and 100.
+- `sha256` (String) The sha256 hash of the file.
+- `state` (String) The host’s current online status from Crowdstrike. Available values: `online`, `offline`, `unknown`.
+- `thumbprint` (String) The thumbprint of the file certificate.
+- `total_score` (Number) The total score from Tanium.
+- `version` (String) The operating system semantic version.
+- `version_operator` (String) The version comparison operator for crowdstrike. Available values: `>`, `>=`, `<`, `<=`, `==`.
+
+
+
+### Nested Schema for `match`
+
+Optional:
+
+- `platform` (String) The platform of the device. Available values: `windows`, `mac`, `linux`, `android`, `ios`, `chromeos`.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_device_posture_rule.example /
+```
diff --git a/docs/resources/zero_trust_device_profiles.md b/docs/resources/zero_trust_device_profiles.md
new file mode 100644
index 0000000000..4cd3c8388c
--- /dev/null
+++ b/docs/resources/zero_trust_device_profiles.md
@@ -0,0 +1,74 @@
+---
+page_title: "cloudflare_zero_trust_device_profiles Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Device Settings Policy resource. Device policies configure settings applied to WARP devices.
+---
+
+# cloudflare_zero_trust_device_profiles (Resource)
+
+Provides a Cloudflare Device Settings Policy resource. Device policies configure settings applied to WARP devices.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_device_profiles" "developer_warp_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Developers WARP settings policy"
+ description = "Developers WARP settings policy description"
+ precedence = 10
+ match = "any(identity.groups.name[*] in {\"Developers\"})"
+ default = false
+ enabled = true
+ allow_mode_switch = true
+ allow_updates = true
+ allowed_to_leave = true
+ auto_connect = 0
+ captive_portal = 5
+ disable_auto_fallback = true
+ support_url = "https://cloudflare.com"
+ switch_locked = true
+ service_mode_v2_mode = "warp"
+ service_mode_v2_port = 3000
+ exclude_office_ips = false
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `description` (String) Description of Policy.
+- `name` (String) Name of the policy.
+
+### Optional
+
+- `allow_mode_switch` (Boolean) Whether to allow mode switch for this policy.
+- `allow_updates` (Boolean) Whether to allow updates under this policy.
+- `allowed_to_leave` (Boolean) Whether to allow devices to leave the organization. Defaults to `true`.
+- `auto_connect` (Number) The amount of time in seconds to reconnect after having been disabled.
+- `captive_portal` (Number) The captive portal value for this policy. Defaults to `180`.
+- `default` (Boolean) Whether the policy refers to the default account policy.
+- `disable_auto_fallback` (Boolean) Whether to disable auto fallback for this policy.
+- `enabled` (Boolean) Whether the policy is enabled (cannot be set for default policies). Defaults to `true`.
+- `exclude_office_ips` (Boolean) Whether to add Microsoft IPs to split tunnel exclusions.
+- `match` (String) Wirefilter expression to match a device against when evaluating whether this policy should take effect for that device.
+- `precedence` (Number) The precedence of the policy. Lower values indicate higher precedence.
+- `service_mode_v2_mode` (String) The service mode. Available values: `1dot1`, `warp`, `proxy`, `posture_only`, `warp_tunnel_only`. Defaults to `warp`.
+- `service_mode_v2_port` (Number) The port to use for the proxy service mode. Required when using `service_mode_v2_mode`.
+- `support_url` (String) The support URL that will be opened when sending feedback.
+- `switch_locked` (Boolean) Enablement of the ZT client switch lock.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# For default device settings policies you must use "default" as the policy ID.
+$ terraform import cloudflare_zero_trust_device_profiles.example /
+```
diff --git a/docs/resources/zero_trust_dex_test.md b/docs/resources/zero_trust_dex_test.md
new file mode 100644
index 0000000000..3ef3018bf4
--- /dev/null
+++ b/docs/resources/zero_trust_dex_test.md
@@ -0,0 +1,64 @@
+---
+page_title: "cloudflare_zero_trust_dex_test Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Device Dex Test resource. Device Dex Tests allow for building location-aware device settings policies.
+---
+
+# cloudflare_zero_trust_dex_test (Resource)
+
+Provides a Cloudflare Device Dex Test resource. Device Dex Tests allow for building location-aware device settings policies.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_dex_test" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GET homepage"
+ description = "Send a HTTP GET request to the home endpoint every half hour."
+ interval = "0h30m0s"
+ enabled = true
+ data {
+ host = "https://example.com/home"
+ kind = "http"
+ method = "GET"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `data` (Block List, Min: 1, Max: 1) The configuration object which contains the details for the WARP client to conduct the test. (see [below for nested schema](#nestedblock--data))
+- `description` (String) Additional details about the test.
+- `enabled` (Boolean) Determines whether or not the test is active.
+- `interval` (String) How often the test will run.
+- `name` (String) The name of the Device Dex Test. Must be unique.
+
+### Read-Only
+
+- `created` (String) Timestamp of when the Dex Test was created.
+- `id` (String) The ID of this resource.
+- `updated` (String) Timestamp of when the Dex Test was last updated.
+
+
+### Nested Schema for `data`
+
+Required:
+
+- `host` (String) The host URL for `http` test `kind`. For `traceroute`, it must be a valid hostname or IP address.
+- `kind` (String) The type of Device Dex Test. Available values: `http`, `traceroute`.
+
+Optional:
+
+- `method` (String) The http request method. Available values: `GET`.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_dex_test.example /
+```
diff --git a/docs/resources/zero_trust_dlp_profile.md b/docs/resources/zero_trust_dlp_profile.md
new file mode 100644
index 0000000000..4ca3269a46
--- /dev/null
+++ b/docs/resources/zero_trust_dlp_profile.md
@@ -0,0 +1,148 @@
+---
+page_title: "cloudflare_zero_trust_dlp_profile Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare DLP Profile resource. Data Loss Prevention profiles
+ are a set of entries that can be matched in HTTP bodies or files.
+ They are referenced in Zero Trust Gateway rules.
+---
+
+# cloudflare_zero_trust_dlp_profile (Resource)
+
+Provides a Cloudflare DLP Profile resource. Data Loss Prevention profiles
+are a set of entries that can be matched in HTTP bodies or files.
+They are referenced in Zero Trust Gateway rules.
+
+## Example Usage
+
+```terraform
+# Predefined profile must be imported, cannot be created
+resource "cloudflare_zero_trust_dlp_profile" "creds" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Credentials and Secrets"
+ type = "predefined"
+ allowed_match_count = 3
+
+ entry {
+ enabled = true
+ name = "Amazon AWS Access Key ID"
+ id = "d8fcfc9c-773c-405e-8426-21ecbb67ba93"
+ }
+ entry {
+ enabled = false
+ id = "2c0e33e1-71da-40c8-aad3-32e674ad3d96"
+ name = "Amazon AWS Secret Access Key"
+ }
+ entry {
+ enabled = true
+ id = "4e92c006-3802-4dff-bbe1-8e1513b1c92a"
+ name = "Microsoft Azure Client Secret"
+ }
+ entry {
+ enabled = false
+ id = "5c713294-2375-4904-abcf-e4a15be4d592"
+ name = "SSH Private Key"
+ }
+ entry {
+ enabled = true
+ id = "6c6579e4-d832-42d5-905c-8e53340930f2"
+ name = "Google GCP API Key"
+ }
+}
+
+# Custom profile
+resource "cloudflare_zero_trust_dlp_profile" "example_custom" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Example Custom Profile"
+ description = "A profile with example entries"
+ type = "custom"
+ allowed_match_count = 0
+
+ entry {
+ name = "Matches visa credit cards"
+ enabled = true
+ pattern {
+ regex = "4\\d{3}([-\\. ])?\\d{4}([-\\. ])?\\d{4}([-\\. ])?\\d{4}"
+ validation = "luhn"
+ }
+ }
+
+ entry {
+ name = "Matches diners club card"
+ enabled = true
+ pattern {
+ regex = "(?:0[0-5]|[68][0-9])[0-9]{11}"
+ validation = "luhn"
+ }
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `allowed_match_count` (Number) Related DLP policies will trigger when the match count exceeds the number set.
+- `entry` (Block Set, Min: 1) List of entries to apply to the profile. (see [below for nested schema](#nestedblock--entry))
+- `name` (String) Name of the profile. **Modifying this attribute will force creation of a new resource.**
+- `type` (String) The type of the profile. Available values: `custom`, `predefined`. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `context_awareness` (Block List, Max: 1) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedblock--context_awareness))
+- `description` (String) Brief summary of the profile and its intended use.
+- `ocr_enabled` (Boolean) If true, scan images via OCR to determine if any text present matches filters.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `entry`
+
+Required:
+
+- `name` (String) Name of the entry to deploy.
+
+Optional:
+
+- `enabled` (Boolean) Whether the entry is active. Defaults to `false`.
+- `id` (String) Unique entry identifier.
+- `pattern` (Block List, Max: 1) (see [below for nested schema](#nestedblock--entry--pattern))
+
+
+### Nested Schema for `entry.pattern`
+
+Required:
+
+- `regex` (String) The regex that defines the pattern.
+
+Optional:
+
+- `validation` (String) The validation algorithm to apply with this pattern.
+
+
+
+
+### Nested Schema for `context_awareness`
+
+Required:
+
+- `enabled` (Boolean) Scan the context of predefined entries to only return matches surrounded by keywords.
+- `skip` (Block List, Min: 1, Max: 1) Content types to exclude from context analysis and return all matches. (see [below for nested schema](#nestedblock--context_awareness--skip))
+
+
+### Nested Schema for `context_awareness.skip`
+
+Required:
+
+- `files` (Boolean) Return all matches, regardless of context analysis result, if the data is a file.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_dlp_profile.example /
+```
diff --git a/docs/resources/zero_trust_dns_location.md b/docs/resources/zero_trust_dns_location.md
new file mode 100644
index 0000000000..7d8d806280
--- /dev/null
+++ b/docs/resources/zero_trust_dns_location.md
@@ -0,0 +1,72 @@
+---
+page_title: "cloudflare_zero_trust_dns_location Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Teams Location resource. Teams Locations are
+ referenced when creating secure web gateway policies.
+---
+
+# cloudflare_zero_trust_dns_location (Resource)
+
+Provides a Cloudflare Teams Location resource. Teams Locations are
+referenced when creating secure web gateway policies.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_dns_location" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ client_default = true
+ ecs_support = false
+
+ networks {
+ network = "203.0.113.1/32"
+ }
+
+ networks {
+ network = "203.0.113.2/32"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) Name of the teams location.
+
+### Optional
+
+- `client_default` (Boolean) Indicator that this is the default location.
+- `ecs_support` (Boolean) Indicator that this location needs to resolve EDNS queries.
+- `networks` (Block Set) The networks CIDRs that comprise the location. (see [below for nested schema](#nestedblock--networks))
+
+### Read-Only
+
+- `anonymized_logs_enabled` (Boolean) Indicator that anonymized logs are enabled.
+- `doh_subdomain` (String) The FQDN that DoH clients should be pointed at.
+- `id` (String) The ID of this resource.
+- `ip` (String) Client IP address.
+- `ipv4_destination` (String) IP to direct all IPv4 DNS queries to.
+- `policy_ids` (List of String)
+
+
+### Nested Schema for `networks`
+
+Required:
+
+- `network` (String) CIDR notation representation of the network IP.
+
+Read-Only:
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_dns_location.example /
+```
diff --git a/docs/resources/zero_trust_gateway_policy.md b/docs/resources/zero_trust_gateway_policy.md
new file mode 100644
index 0000000000..497ee6fc1f
--- /dev/null
+++ b/docs/resources/zero_trust_gateway_policy.md
@@ -0,0 +1,200 @@
+---
+page_title: "cloudflare_zero_trust_gateway_policy Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Teams rule resource. Teams rules comprise secure web gateway policies.
+---
+
+# cloudflare_zero_trust_gateway_policy (Resource)
+
+Provides a Cloudflare Teams rule resource. Teams rules comprise secure web gateway policies.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_gateway_policy" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ description = "desc"
+ precedence = 1
+ action = "block"
+ filters = ["http"]
+ traffic = "http.request.uri == \"https://www.example.com/malicious\""
+ rule_settings {
+ block_page_enabled = true
+ block_page_reason = "access not permitted"
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `action` (String) The action executed by matched teams rule. Available values: `allow`, `block`, `safesearch`, `ytrestricted`, `on`, `off`, `scan`, `noscan`, `isolate`, `noisolate`, `override`, `l4_override`, `egress`, `audit_ssh`, `resolve`.
+- `description` (String) The description of the teams rule.
+- `name` (String) The name of the teams rule.
+- `precedence` (Number) The evaluation precedence of the teams rule.
+
+### Optional
+
+- `device_posture` (String) The wirefilter expression to be used for device_posture check matching.
+- `enabled` (Boolean) Indicator of rule enablement.
+- `filters` (List of String) The protocol or layer to evaluate the traffic and identity expressions.
+- `identity` (String) The wirefilter expression to be used for identity matching.
+- `rule_settings` (Block List, Max: 1) Additional rule settings. (see [below for nested schema](#nestedblock--rule_settings))
+- `traffic` (String) The wirefilter expression to be used for traffic matching.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `version` (Number)
+
+
+### Nested Schema for `rule_settings`
+
+Optional:
+
+- `add_headers` (Map of String) Add custom headers to allowed requests in the form of key-value pairs.
+- `allow_child_bypass` (Boolean) Allow parent MSP accounts to enable bypass their children's rules.
+- `audit_ssh` (Block List, Max: 1) Settings for auditing SSH usage. (see [below for nested schema](#nestedblock--rule_settings--audit_ssh))
+- `biso_admin_controls` (Block List, Max: 1) Configure how browser isolation behaves. (see [below for nested schema](#nestedblock--rule_settings--biso_admin_controls))
+- `block_page_enabled` (Boolean) Indicator of block page enablement.
+- `block_page_reason` (String) The displayed reason for a user being blocked.
+- `bypass_parent_rule` (Boolean) Allow child MSP accounts to bypass their parent's rule.
+- `check_session` (Block List, Max: 1) Configure how session check behaves. (see [below for nested schema](#nestedblock--rule_settings--check_session))
+- `dns_resolvers` (Block List, Max: 1) Add your own custom resolvers to route queries that match the resolver policy. Cannot be used when resolve_dns_through_cloudflare is set. DNS queries will route to the address closest to their origin. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers))
+- `egress` (Block List, Max: 1) Configure how Proxy traffic egresses. Can be set for rules with Egress action and Egress filter. Can be omitted to indicate local egress via Warp IPs. (see [below for nested schema](#nestedblock--rule_settings--egress))
+- `ignore_cname_category_matches` (Boolean) Set to true, to ignore the category matches at CNAME domains in a response.
+- `insecure_disable_dnssec_validation` (Boolean) Disable DNSSEC validation (must be Allow rule).
+- `ip_categories` (Boolean) Turns on IP category based filter on dns if the rule contains dns category checks.
+- `l4override` (Block List, Max: 1) Settings to forward layer 4 traffic. (see [below for nested schema](#nestedblock--rule_settings--l4override))
+- `notification_settings` (Block List, Max: 1) Notification settings on a block rule. (see [below for nested schema](#nestedblock--rule_settings--notification_settings))
+- `override_host` (String) The host to override matching DNS queries with.
+- `override_ips` (List of String) The IPs to override matching DNS queries with.
+- `payload_log` (Block List, Max: 1) Configure DLP Payload Logging settings for this rule. (see [below for nested schema](#nestedblock--rule_settings--payload_log))
+- `resolve_dns_through_cloudflare` (Boolean) Enable sending queries that match the resolver policy to Cloudflare's default 1.1.1.1 DNS resolver. Cannot be set when `dns_resolvers` are specified.
+- `untrusted_cert` (Block List, Max: 1) Configure untrusted certificate settings for this rule. (see [below for nested schema](#nestedblock--rule_settings--untrusted_cert))
+
+
+### Nested Schema for `rule_settings.audit_ssh`
+
+Required:
+
+- `command_logging` (Boolean) Log all SSH commands.
+
+
+
+### Nested Schema for `rule_settings.biso_admin_controls`
+
+Optional:
+
+- `disable_clipboard_redirection` (Boolean) Disable clipboard redirection.
+- `disable_copy_paste` (Boolean) Disable copy-paste.
+- `disable_download` (Boolean) Disable download.
+- `disable_keyboard` (Boolean) Disable keyboard usage.
+- `disable_printing` (Boolean) Disable printing.
+- `disable_upload` (Boolean) Disable upload.
+
+
+
+### Nested Schema for `rule_settings.check_session`
+
+Required:
+
+- `duration` (String) Configure how fresh the session needs to be to be considered valid.
+- `enforce` (Boolean) Enable session enforcement for this rule.
+
+
+
+### Nested Schema for `rule_settings.dns_resolvers`
+
+Optional:
+
+- `ipv4` (Block List, Max: 10) IPv4 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv4))
+- `ipv6` (Block List, Max: 10) IPv6 resolvers. (see [below for nested schema](#nestedblock--rule_settings--dns_resolvers--ipv6))
+
+
+### Nested Schema for `rule_settings.dns_resolvers.ipv4`
+
+Required:
+
+- `ip` (String) The IPv4 or IPv6 address of the upstream resolver.
+
+Optional:
+
+- `port` (Number) A port number to use for the upstream resolver. Defaults to `53`.
+- `route_through_private_network` (Boolean) Whether to connect to this resolver over a private network. Must be set when `vnet_id` is set.
+- `vnet_id` (String) specify a virtual network for this resolver. Uses default virtual network id if omitted.
+
+
+
+### Nested Schema for `rule_settings.dns_resolvers.ipv6`
+
+Required:
+
+- `ip` (String) The IPv4 or IPv6 address of the upstream resolver.
+
+Optional:
+
+- `port` (Number) A port number to use for the upstream resolver. Defaults to `53`.
+- `route_through_private_network` (Boolean) Whether to connect to this resolver over a private network. Must be set when `vnet_id` is set.
+- `vnet_id` (String) specify a virtual network for this resolver. Uses default virtual network id if omitted.
+
+
+
+
+### Nested Schema for `rule_settings.egress`
+
+Required:
+
+- `ipv4` (String) The IPv4 address to be used for egress.
+- `ipv6` (String) The IPv6 range to be used for egress.
+
+Optional:
+
+- `ipv4_fallback` (String) The IPv4 address to be used for egress in the event of an error egressing with the primary IPv4. Can be '0.0.0.0' to indicate local egreass via Warp IPs.
+
+
+
+### Nested Schema for `rule_settings.l4override`
+
+Required:
+
+- `ip` (String) Override IP to forward traffic to.
+- `port` (Number) Override Port to forward traffic to.
+
+
+
+### Nested Schema for `rule_settings.notification_settings`
+
+Optional:
+
+- `enabled` (Boolean) Enable notification settings.
+- `message` (String) Notification content.
+- `support_url` (String) Support URL to show in the notification.
+
+
+
+### Nested Schema for `rule_settings.payload_log`
+
+Required:
+
+- `enabled` (Boolean) Enable or disable DLP Payload Logging for this rule.
+
+
+
+### Nested Schema for `rule_settings.untrusted_cert`
+
+Optional:
+
+- `action` (String) Action to be taken when the SSL certificate of upstream is invalid. Available values: `pass_through`, `block`, `error`.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_gateway_policy.example /
+```
diff --git a/docs/resources/zero_trust_gateway_proxy_endpoint.md b/docs/resources/zero_trust_gateway_proxy_endpoint.md
new file mode 100644
index 0000000000..fa6336f85a
--- /dev/null
+++ b/docs/resources/zero_trust_gateway_proxy_endpoint.md
@@ -0,0 +1,45 @@
+---
+page_title: "cloudflare_zero_trust_gateway_proxy_endpoint Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Teams Proxy Endpoint resource. Teams Proxy
+ Endpoints are used for pointing proxy clients at Cloudflare Secure
+ Gateway.
+---
+
+# cloudflare_zero_trust_gateway_proxy_endpoint (Resource)
+
+Provides a Cloudflare Teams Proxy Endpoint resource. Teams Proxy
+Endpoints are used for pointing proxy clients at Cloudflare Secure
+Gateway.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_gateway_proxy_endpoint" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ ips = ["192.0.2.0/24"]
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `ips` (Set of String) The networks CIDRs that will be allowed to initiate proxy connections.
+- `name` (String) Name of the teams proxy endpoint.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `subdomain` (String) The FQDN that proxy clients should be pointed at.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_gateway_proxy_endpoint.example /
+```
diff --git a/docs/resources/zero_trust_gateway_settings.md b/docs/resources/zero_trust_gateway_settings.md
new file mode 100644
index 0000000000..3e60781019
--- /dev/null
+++ b/docs/resources/zero_trust_gateway_settings.md
@@ -0,0 +1,266 @@
+---
+page_title: "cloudflare_zero_trust_gateway_settings Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Teams Account resource. The Teams Account
+ resource defines configuration for secure web gateway.
+---
+
+# cloudflare_zero_trust_gateway_settings (Resource)
+
+Provides a Cloudflare Teams Account resource. The Teams Account
+resource defines configuration for secure web gateway.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_gateway_settings" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tls_decrypt_enabled = true
+ protocol_detection_enabled = true
+
+ block_page {
+ footer_text = "hello"
+ header_text = "hello"
+ logo_path = "https://example.com/logo.jpg"
+ background_color = "#000000"
+ }
+
+ body_scanning {
+ inspection_mode = "deep"
+ }
+
+ antivirus {
+ enabled_download_phase = true
+ enabled_upload_phase = false
+ fail_closed = true
+ notification_settings {
+ enabled = true
+ message = "you are blocked"
+ support_url = "https://example.com/blocked"
+ }
+ }
+
+ fips {
+ tls = true
+ }
+
+ proxy {
+ tcp = true
+ udp = true
+ root_ca = true
+ virtual_ip = false
+ }
+
+ url_browser_isolation_enabled = true
+
+ logging {
+ redact_pii = true
+ settings_by_rule_type {
+ dns {
+ log_all = false
+ log_blocks = true
+ }
+ http {
+ log_all = true
+ log_blocks = true
+ }
+ l4 {
+ log_all = false
+ log_blocks = true
+ }
+ }
+ }
+
+ extended_email_matching {
+ enabled = true
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+
+### Optional
+
+- `activity_log_enabled` (Boolean) Whether to enable the activity log.
+- `antivirus` (Block List, Max: 1) Configuration block for antivirus traffic scanning. (see [below for nested schema](#nestedblock--antivirus))
+- `block_page` (Block List, Max: 1) Configuration for a custom block page. (see [below for nested schema](#nestedblock--block_page))
+- `body_scanning` (Block List, Max: 1) Configuration for body scanning. (see [below for nested schema](#nestedblock--body_scanning))
+- `custom_certificate` (Block List, Max: 1) Configuration for custom certificates / BYO-PKI. (see [below for nested schema](#nestedblock--custom_certificate))
+- `extended_email_matching` (Block List, Max: 1) Configuration for extended e-mail matching. (see [below for nested schema](#nestedblock--extended_email_matching))
+- `fips` (Block List, Max: 1) Configure compliance with Federal Information Processing Standards. (see [below for nested schema](#nestedblock--fips))
+- `logging` (Block List, Max: 1) (see [below for nested schema](#nestedblock--logging))
+- `non_identity_browser_isolation_enabled` (Boolean) Enable non-identity onramp for Browser Isolation. Defaults to `false`.
+- `payload_log` (Block List, Max: 1) Configuration for DLP Payload Logging. (see [below for nested schema](#nestedblock--payload_log))
+- `protocol_detection_enabled` (Boolean) Indicator that protocol detection is enabled.
+- `proxy` (Block List, Max: 1) Configuration block for specifying which protocols are proxied. (see [below for nested schema](#nestedblock--proxy))
+- `ssh_session_log` (Block List, Max: 1) Configuration for SSH Session Logging. (see [below for nested schema](#nestedblock--ssh_session_log))
+- `tls_decrypt_enabled` (Boolean) Indicator that decryption of TLS traffic is enabled.
+- `url_browser_isolation_enabled` (Boolean) Safely browse websites in Browser Isolation through a URL. Defaults to `false`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `antivirus`
+
+Required:
+
+- `enabled_download_phase` (Boolean) Scan on file download.
+- `enabled_upload_phase` (Boolean) Scan on file upload.
+- `fail_closed` (Boolean) Block requests for files that cannot be scanned.
+
+Optional:
+
+- `notification_settings` (Block List, Max: 1) Set notifications for antivirus. (see [below for nested schema](#nestedblock--antivirus--notification_settings))
+
+
+### Nested Schema for `antivirus.notification_settings`
+
+Optional:
+
+- `enabled` (Boolean) Enable notification settings.
+- `message` (String) Notification content.
+- `support_url` (String) Support URL to show in the notification.
+
+
+
+
+### Nested Schema for `block_page`
+
+Optional:
+
+- `background_color` (String) Hex code of block page background color.
+- `enabled` (Boolean) Indicator of enablement.
+- `footer_text` (String) Block page footer text.
+- `header_text` (String) Block page header text.
+- `logo_path` (String) URL of block page logo.
+- `mailto_address` (String) Admin email for users to contact.
+- `mailto_subject` (String) Subject line for emails created from block page.
+- `name` (String) Name of block page configuration.
+
+
+
+### Nested Schema for `body_scanning`
+
+Required:
+
+- `inspection_mode` (String) Body scanning inspection mode. Available values: `deep`, `shallow`.
+
+
+
+### Nested Schema for `custom_certificate`
+
+Required:
+
+- `enabled` (Boolean) Whether TLS encryption should use a custom certificate.
+
+Optional:
+
+- `id` (String) ID of custom certificate.
+
+Read-Only:
+
+- `updated_at` (String)
+
+
+
+### Nested Schema for `extended_email_matching`
+
+Required:
+
+- `enabled` (Boolean) Whether e-mails should be matched on all variants of user emails (with + or . modifiers) in Firewall policies.
+
+
+
+### Nested Schema for `fips`
+
+Optional:
+
+- `tls` (Boolean) Only allow FIPS-compliant TLS configuration.
+
+
+
+### Nested Schema for `logging`
+
+Required:
+
+- `redact_pii` (Boolean) Redact personally identifiable information from activity logging (PII fields are: source IP, user email, user ID, device ID, URL, referrer, user agent).
+- `settings_by_rule_type` (Block List, Min: 1, Max: 1) Represents whether all requests are logged or only the blocked requests are slogged in DNS, HTTP and L4 filters. (see [below for nested schema](#nestedblock--logging--settings_by_rule_type))
+
+
+### Nested Schema for `logging.settings_by_rule_type`
+
+Required:
+
+- `dns` (Block List, Min: 1, Max: 1) Logging configuration for DNS requests. (see [below for nested schema](#nestedblock--logging--settings_by_rule_type--dns))
+- `http` (Block List, Min: 1, Max: 1) Logging configuration for HTTP requests. (see [below for nested schema](#nestedblock--logging--settings_by_rule_type--http))
+- `l4` (Block List, Min: 1, Max: 1) Logging configuration for layer 4 requests. (see [below for nested schema](#nestedblock--logging--settings_by_rule_type--l4))
+
+
+### Nested Schema for `logging.settings_by_rule_type.dns`
+
+Required:
+
+- `log_all` (Boolean) Whether to log all activity.
+- `log_blocks` (Boolean)
+
+
+
+### Nested Schema for `logging.settings_by_rule_type.http`
+
+Required:
+
+- `log_all` (Boolean) Whether to log all activity.
+- `log_blocks` (Boolean)
+
+
+
+### Nested Schema for `logging.settings_by_rule_type.l4`
+
+Required:
+
+- `log_all` (Boolean) Whether to log all activity.
+- `log_blocks` (Boolean)
+
+
+
+
+
+### Nested Schema for `payload_log`
+
+Required:
+
+- `public_key` (String) Public key used to encrypt matched payloads.
+
+
+
+### Nested Schema for `proxy`
+
+Required:
+
+- `root_ca` (Boolean) Whether root ca is enabled account wide for ZT clients.
+- `tcp` (Boolean) Whether gateway proxy is enabled on gateway devices for TCP traffic.
+- `udp` (Boolean) Whether gateway proxy is enabled on gateway devices for UDP traffic.
+- `virtual_ip` (Boolean) Whether virtual IP (CGNAT) is enabled account wide and will override existing local interface IP for ZT clients.
+
+
+
+### Nested Schema for `ssh_session_log`
+
+Required:
+
+- `public_key` (String) Public key used to encrypt ssh session.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_gateway_settings.example
+```
diff --git a/docs/resources/zero_trust_key_access_key_configuration.md b/docs/resources/zero_trust_key_access_key_configuration.md
new file mode 100644
index 0000000000..4ce2f69deb
--- /dev/null
+++ b/docs/resources/zero_trust_key_access_key_configuration.md
@@ -0,0 +1,30 @@
+---
+page_title: "cloudflare_zero_trust_key_access_key_configuration Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Access Keys Configuration defines the rotation policy for the keys
+ that access will use to sign data.
+---
+
+# cloudflare_zero_trust_key_access_key_configuration (Resource)
+
+Access Keys Configuration defines the rotation policy for the keys
+that access will use to sign data.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+
+### Optional
+
+- `key_rotation_interval_days` (Number) Number of days to trigger a rotation of the keys.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/zero_trust_list.md b/docs/resources/zero_trust_list.md
new file mode 100644
index 0000000000..f82ca00626
--- /dev/null
+++ b/docs/resources/zero_trust_list.md
@@ -0,0 +1,60 @@
+---
+page_title: "cloudflare_zero_trust_list Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Teams List resource. Teams lists are
+ referenced when creating secure web gateway policies or device
+ posture rules.
+---
+
+# cloudflare_zero_trust_list (Resource)
+
+Provides a Cloudflare Teams List resource. Teams lists are
+referenced when creating secure web gateway policies or device
+posture rules.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_list" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Corporate devices"
+ type = "SERIAL"
+ description = "Serial numbers for all corporate devices."
+ items = ["8GE8721REF", "5RE8543EGG", "1YE2880LNP"]
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `name` (String) Name of the teams list.
+- `type` (String) The teams list type. Available values: `IP`, `SERIAL`, `URL`, `DOMAIN`, `EMAIL`.
+
+### Optional
+
+- `description` (String) The description of the teams list.
+- `items` (Set of String) The items of the teams list.
+- `items_with_description` (Set of Object) The items of the teams list that has explicit description. (see [below for nested schema](#nestedatt--items_with_description))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `items_with_description`
+
+Optional:
+
+- `description` (String)
+- `value` (String)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_list.example /
+```
diff --git a/docs/resources/zero_trust_local_fallback_domain.md b/docs/resources/zero_trust_local_fallback_domain.md
new file mode 100644
index 0000000000..66587860f8
--- /dev/null
+++ b/docs/resources/zero_trust_local_fallback_domain.md
@@ -0,0 +1,44 @@
+---
+page_title: "cloudflare_zero_trust_local_fallback_domain Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Fallback Domain resource. Fallback domains are
+ used to ignore DNS requests to a given list of domains. These DNS
+ requests will be passed back to other DNS servers configured on
+ existing network interfaces on the device.
+---
+
+# cloudflare_zero_trust_local_fallback_domain (Resource)
+
+Provides a Cloudflare Fallback Domain resource. Fallback domains are
+used to ignore DNS requests to a given list of domains. These DNS
+requests will be passed back to other DNS servers configured on
+existing network interfaces on the device.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `domains` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--domains))
+
+### Optional
+
+- `policy_id` (String) The settings policy for which to configure this fallback domain policy.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `domains`
+
+Optional:
+
+- `description` (String) A description of the fallback domain, displayed in the client UI.
+- `dns_server` (List of String) A list of IP addresses to handle domain resolution.
+- `suffix` (String) The domain suffix to match when resolving locally.
+
+
diff --git a/docs/resources/zero_trust_risk_behavior.md b/docs/resources/zero_trust_risk_behavior.md
new file mode 100644
index 0000000000..e3665a1bb6
--- /dev/null
+++ b/docs/resources/zero_trust_risk_behavior.md
@@ -0,0 +1,33 @@
+---
+page_title: "cloudflare_zero_trust_risk_behavior Resource - Cloudflare"
+subcategory: ""
+description: |-
+ The Risk Behavior https://developers.cloudflare.com/cloudflare-one/insights/risk-score/ resource allows you to configure Cloudflare Risk Behaviors for an account.
+---
+
+# cloudflare_zero_trust_risk_behavior (Resource)
+
+The [Risk Behavior](https://developers.cloudflare.com/cloudflare-one/insights/risk-score/) resource allows you to configure Cloudflare Risk Behaviors for an account.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+
+### Optional
+
+- `behavior` (Block Set) Zero Trust risk behaviors configured on this account (see [below for nested schema](#nestedblock--behavior))
+
+
+### Nested Schema for `behavior`
+
+Required:
+
+- `enabled` (Boolean) Whether this risk behavior type is enabled.
+- `name` (String) Name of this risk behavior type
+- `risk_level` (String) Risk level. Available values: `low`, `medium`, `high`
+
+
diff --git a/docs/resources/zero_trust_split_tunnel.md b/docs/resources/zero_trust_split_tunnel.md
new file mode 100644
index 0000000000..fabae12d08
--- /dev/null
+++ b/docs/resources/zero_trust_split_tunnel.md
@@ -0,0 +1,41 @@
+---
+page_title: "cloudflare_zero_trust_split_tunnel Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Split Tunnel resource. Split tunnels are used to either
+ include or exclude lists of routes from the WARP client's tunnel.
+---
+
+# cloudflare_zero_trust_split_tunnel (Resource)
+
+Provides a Cloudflare Split Tunnel resource. Split tunnels are used to either
+include or exclude lists of routes from the WARP client's tunnel.
+
+
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `mode` (String) The mode of the split tunnel policy. Available values: `include`, `exclude`.
+- `tunnels` (Block Set, Min: 1) The value of the tunnel attributes. (see [below for nested schema](#nestedblock--tunnels))
+
+### Optional
+
+- `policy_id` (String) The settings policy for which to configure this split tunnel policy.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `tunnels`
+
+Optional:
+
+- `address` (String) The address for the tunnel.
+- `description` (String) A description for the tunnel.
+- `host` (String) The domain name for the tunnel.
+
+
diff --git a/docs/resources/zero_trust_tunnel_cloudflared.md b/docs/resources/zero_trust_tunnel_cloudflared.md
new file mode 100644
index 0000000000..fa58650975
--- /dev/null
+++ b/docs/resources/zero_trust_tunnel_cloudflared.md
@@ -0,0 +1,50 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_cloudflared Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Tunnel exposes applications running on your local web server on any
+ network with an internet connection without manually adding DNS
+ records or configuring a firewall or router.
+---
+
+# cloudflare_zero_trust_tunnel_cloudflared (Resource)
+
+Tunnel exposes applications running on your local web server on any
+network with an internet connection without manually adding DNS
+records or configuring a firewall or router.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "my-tunnel"
+ secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `name` (String) A user-friendly name chosen when the tunnel is created. **Modifying this attribute will force creation of a new resource.**
+- `secret` (String, Sensitive) 32 or more bytes, encoded as a base64 string. The Create Argo Tunnel endpoint sets this as the tunnel's password. Anyone wishing to run the tunnel needs this password. **Modifying this attribute will force creation of a new resource.**
+
+### Optional
+
+- `config_src` (String) Indicates if this is a locally or remotely configured tunnel. If `local`, manage the tunnel using a YAML file on the origin machine. If `cloudflare`, manage the tunnel on the Zero Trust dashboard or using tunnel_config, tunnel_route or tunnel_virtual_network resources. Available values: `local`, `cloudflare`. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `cname` (String) Usable CNAME for accessing the Tunnel.
+- `id` (String) The ID of this resource.
+- `tunnel_token` (String, Sensitive) Token used by a connector to authenticate and run the tunnel.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_tunnel_cloudflared.example /
+```
diff --git a/docs/resources/zero_trust_tunnel_cloudflared_config.md b/docs/resources/zero_trust_tunnel_cloudflared_config.md
new file mode 100644
index 0000000000..125559e38d
--- /dev/null
+++ b/docs/resources/zero_trust_tunnel_cloudflared_config.md
@@ -0,0 +1,212 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_cloudflared_config Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a Cloudflare Tunnel configuration resource.
+---
+
+# cloudflare_zero_trust_tunnel_cloudflared_config (Resource)
+
+Provides a Cloudflare Tunnel configuration resource.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example_tunnel" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example_tunnel"
+ secret = "<32 character secret>"
+}
+
+resource "cloudflare_zero_trust_tunnel_cloudflared_config" "example_config" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.example_tunnel.id
+
+ config {
+ warp_routing {
+ enabled = true
+ }
+ origin_request {
+ connect_timeout = "1m0s"
+ tls_timeout = "1m0s"
+ tcp_keep_alive = "1m0s"
+ no_happy_eyeballs = false
+ keep_alive_connections = 1024
+ keep_alive_timeout = "1m0s"
+ http_host_header = "baz"
+ origin_server_name = "foobar"
+ ca_pool = "/path/to/unsigned/ca/pool"
+ no_tls_verify = false
+ disable_chunked_encoding = false
+ bastion_mode = false
+ proxy_address = "10.0.0.1"
+ proxy_port = "8123"
+ proxy_type = "socks"
+ ip_rules {
+ prefix = "/web"
+ ports = [80, 443]
+ allow = false
+ }
+ }
+ ingress_rule {
+ hostname = "foo"
+ path = "/bar"
+ service = "http://10.0.0.2:8080"
+ origin_request {
+ connect_timeout = "2m0s"
+ access {
+ required = true
+ team_name = "terraform"
+ aud_tag = ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
+ }
+ }
+ }
+ ingress_rule {
+ service = "https://10.0.0.3:8081"
+ }
+ }
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource.
+- `config` (Block List, Min: 1, Max: 1) Configuration block for Tunnel Configuration. (see [below for nested schema](#nestedblock--config))
+- `tunnel_id` (String) Identifier of the Tunnel to target for this configuration.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `config`
+
+Required:
+
+- `ingress_rule` (Block List, Min: 1) Each incoming request received by cloudflared causes cloudflared to send a request to a local service. This section configures the rules that determine which requests are sent to which local services. Last rule must match all requests, e.g `service = "http_status:503"`. [Read more](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/local/local-management/ingress/). (see [below for nested schema](#nestedblock--config--ingress_rule))
+
+Optional:
+
+- `origin_request` (Block List, Max: 1) (see [below for nested schema](#nestedblock--config--origin_request))
+- `warp_routing` (Block List, Max: 1) If you're exposing a [private network](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/private-net/), you need to add the `warp-routing` key and set it to `true`. (see [below for nested schema](#nestedblock--config--warp_routing))
+
+
+### Nested Schema for `config.ingress_rule`
+
+Required:
+
+- `service` (String) Name of the service to which the request will be sent.
+
+Optional:
+
+- `hostname` (String) Hostname to match the incoming request with. If the hostname matches, the request will be sent to the service.
+- `origin_request` (Block List, Max: 1) (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request))
+- `path` (String) Path of the incoming request. If the path matches, the request will be sent to the local service.
+
+
+### Nested Schema for `config.ingress_rule.origin_request`
+
+Optional:
+
+- `access` (Block List, Max: 1) Access rules for the ingress service. (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request--access))
+- `bastion_mode` (Boolean) Runs as jump host.
+- `ca_pool` (String) Path to the certificate authority (CA) for the certificate of your origin. This option should be used only if your certificate is not signed by Cloudflare. Defaults to `""`.
+- `connect_timeout` (String) Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by `tlsTimeout`. Defaults to `30s`.
+- `disable_chunked_encoding` (Boolean) Disables chunked transfer encoding. Useful if you are running a Web Server Gateway Interface (WSGI) server. Defaults to `false`.
+- `http2_origin` (Boolean) Enables HTTP/2 support for the origin connection. Defaults to `false`.
+- `http_host_header` (String) Sets the HTTP Host header on requests sent to the local service. Defaults to `""`.
+- `ip_rules` (Block Set) IP rules for the proxy service. (see [below for nested schema](#nestedblock--config--ingress_rule--origin_request--ip_rules))
+- `keep_alive_connections` (Number) Maximum number of idle keepalive connections between Tunnel and your origin. This does not restrict the total number of concurrent connections. Defaults to `100`.
+- `keep_alive_timeout` (String) Timeout after which an idle keepalive connection can be discarded. Defaults to `1m30s`.
+- `no_happy_eyeballs` (Boolean) Disable the “happy eyeballs” algorithm for IPv4/IPv6 fallback if your local network has misconfigured one of the protocols. Defaults to `false`.
+- `no_tls_verify` (Boolean) Disables TLS verification of the certificate presented by your origin. Will allow any certificate from the origin to be accepted. Defaults to `false`.
+- `origin_server_name` (String) Hostname that cloudflared should expect from your origin server certificate. Defaults to `""`.
+- `proxy_address` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen address for that proxy. Defaults to `127.0.0.1`.
+- `proxy_port` (Number) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen port for that proxy. If set to zero, an unused port will randomly be chosen. Defaults to `0`.
+- `proxy_type` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures what type of proxy will be started. Available values: `""`, `socks`. Defaults to `""`.
+- `tcp_keep_alive` (String) The timeout after which a TCP keepalive packet is sent on a connection between Tunnel and the origin server. Defaults to `30s`.
+- `tls_timeout` (String) Timeout for completing a TLS handshake to your origin server, if you have chosen to connect Tunnel to an HTTPS server. Defaults to `10s`.
+
+
+### Nested Schema for `config.ingress_rule.origin_request.access`
+
+Optional:
+
+- `aud_tag` (Set of String) Audience tags of the access rule.
+- `required` (Boolean) Whether the access rule is required.
+- `team_name` (String) Name of the team to which the access rule applies.
+
+
+
+### Nested Schema for `config.ingress_rule.origin_request.ip_rules`
+
+Optional:
+
+- `allow` (Boolean) Whether to allow the IP prefix.
+- `ports` (List of Number) Ports to use within the IP rule.
+- `prefix` (String) IP rule prefix.
+
+
+
+
+
+### Nested Schema for `config.origin_request`
+
+Optional:
+
+- `access` (Block List, Max: 1) Access rules for the ingress service. (see [below for nested schema](#nestedblock--config--origin_request--access))
+- `bastion_mode` (Boolean) Runs as jump host.
+- `ca_pool` (String) Path to the certificate authority (CA) for the certificate of your origin. This option should be used only if your certificate is not signed by Cloudflare. Defaults to `""`.
+- `connect_timeout` (String) Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by `tlsTimeout`. Defaults to `30s`.
+- `disable_chunked_encoding` (Boolean) Disables chunked transfer encoding. Useful if you are running a Web Server Gateway Interface (WSGI) server. Defaults to `false`.
+- `http2_origin` (Boolean) Enables HTTP/2 support for the origin connection. Defaults to `false`.
+- `http_host_header` (String) Sets the HTTP Host header on requests sent to the local service. Defaults to `""`.
+- `ip_rules` (Block Set) IP rules for the proxy service. (see [below for nested schema](#nestedblock--config--origin_request--ip_rules))
+- `keep_alive_connections` (Number) Maximum number of idle keepalive connections between Tunnel and your origin. This does not restrict the total number of concurrent connections. Defaults to `100`.
+- `keep_alive_timeout` (String) Timeout after which an idle keepalive connection can be discarded. Defaults to `1m30s`.
+- `no_happy_eyeballs` (Boolean) Disable the “happy eyeballs” algorithm for IPv4/IPv6 fallback if your local network has misconfigured one of the protocols. Defaults to `false`.
+- `no_tls_verify` (Boolean) Disables TLS verification of the certificate presented by your origin. Will allow any certificate from the origin to be accepted. Defaults to `false`.
+- `origin_server_name` (String) Hostname that cloudflared should expect from your origin server certificate. Defaults to `""`.
+- `proxy_address` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen address for that proxy. Defaults to `127.0.0.1`.
+- `proxy_port` (Number) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures the listen port for that proxy. If set to zero, an unused port will randomly be chosen. Defaults to `0`.
+- `proxy_type` (String) cloudflared starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures what type of proxy will be started. Available values: `""`, `socks`. Defaults to `""`.
+- `tcp_keep_alive` (String) The timeout after which a TCP keepalive packet is sent on a connection between Tunnel and the origin server. Defaults to `30s`.
+- `tls_timeout` (String) Timeout for completing a TLS handshake to your origin server, if you have chosen to connect Tunnel to an HTTPS server. Defaults to `10s`.
+
+
+### Nested Schema for `config.origin_request.access`
+
+Optional:
+
+- `aud_tag` (Set of String) Audience tags of the access rule.
+- `required` (Boolean) Whether the access rule is required.
+- `team_name` (String) Name of the team to which the access rule applies.
+
+
+
+### Nested Schema for `config.origin_request.ip_rules`
+
+Optional:
+
+- `allow` (Boolean) Whether to allow the IP prefix.
+- `ports` (List of Number) Ports to use within the IP rule.
+- `prefix` (String) IP rule prefix.
+
+
+
+
+### Nested Schema for `config.warp_routing`
+
+Optional:
+
+- `enabled` (Boolean) Whether WARP routing is enabled.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_tunnel_cloudflared_config.example /
+```
diff --git a/docs/resources/zero_trust_tunnel_route.md b/docs/resources/zero_trust_tunnel_route.md
new file mode 100644
index 0000000000..27f46890dc
--- /dev/null
+++ b/docs/resources/zero_trust_tunnel_route.md
@@ -0,0 +1,67 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_route Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource, that manages Cloudflare tunnel routes for Zero
+ Trust. Tunnel routes are used to direct IP traffic through
+ Cloudflare Tunnels.
+---
+
+# cloudflare_zero_trust_tunnel_route (Resource)
+
+Provides a resource, that manages Cloudflare tunnel routes for Zero
+Trust. Tunnel routes are used to direct IP traffic through
+Cloudflare Tunnels.
+
+## Example Usage
+
+```terraform
+# Tunnel route
+resource "cloudflare_zero_trust_tunnel_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415"
+ network = "192.0.2.24/32"
+ comment = "New tunnel route for documentation"
+ virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
+}
+
+# Tunnel with tunnel route
+resource "cloudflare_zero_trust_tunnel_cloudflared" "tunnel" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "my_tunnel"
+ secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
+}
+
+resource "cloudflare_zero_trust_tunnel_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.tunnel.id
+ network = "192.0.2.24/32"
+ comment = "New tunnel route for documentation"
+ virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `network` (String) The IPv4 or IPv6 network that should use this tunnel route, in CIDR notation.
+- `tunnel_id` (String) The ID of the tunnel that will service the tunnel route.
+
+### Optional
+
+- `comment` (String) Description of the tunnel route.
+- `virtual_network_id` (String) The ID of the virtual network for which this route is being added; uses the default virtual network of the account if none is provided. **Modifying this attribute will force creation of a new resource.**
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_tunnel_route.example //
+```
diff --git a/docs/resources/zero_trust_tunnel_virtual_network.md b/docs/resources/zero_trust_tunnel_virtual_network.md
new file mode 100644
index 0000000000..b0a5ac6efb
--- /dev/null
+++ b/docs/resources/zero_trust_tunnel_virtual_network.md
@@ -0,0 +1,50 @@
+---
+page_title: "cloudflare_zero_trust_tunnel_virtual_network Resource - Cloudflare"
+subcategory: ""
+description: |-
+ Provides a resource, that manages Cloudflare tunnel virtual networks
+ for Zero Trust. Tunnel virtual networks are used for segregation of
+ Tunnel IP Routes via Virtualized Networks to handle overlapping
+ private IPs in your origins.
+---
+
+# cloudflare_zero_trust_tunnel_virtual_network (Resource)
+
+Provides a resource, that manages Cloudflare tunnel virtual networks
+for Zero Trust. Tunnel virtual networks are used for segregation of
+Tunnel IP Routes via Virtualized Networks to handle overlapping
+private IPs in your origins.
+
+## Example Usage
+
+```terraform
+resource "cloudflare_zero_trust_tunnel_virtual_network" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "vnet-for-documentation"
+ comment = "New tunnel virtual network for documentation"
+}
+```
+
+## Schema
+
+### Required
+
+- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.**
+- `name` (String) A user-friendly name chosen when the virtual network is created.
+
+### Optional
+
+- `comment` (String) Description of the tunnel virtual network.
+- `is_default_network` (Boolean) Whether this virtual network is the default one for the account. This means IP Routes belong to this virtual network and Teams Clients in the account route through this virtual network, unless specified otherwise for each case.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+$ terraform import cloudflare_zero_trust_tunnel_virtual_network.example /
+```
diff --git a/docs/resources/zone_settings_override.md b/docs/resources/zone_settings_override.md
index a9a05b3992..f23fb86046 100644
--- a/docs/resources/zone_settings_override.md
+++ b/docs/resources/zone_settings_override.md
@@ -33,7 +33,7 @@ feature support by plan.
```terraform
resource "cloudflare_zone_settings_override" "test" {
- zone_id = d41d8cd98f00b204e9800998ecf8427e
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
settings {
brotli = "on"
challenge_ttl = 2700
@@ -106,7 +106,7 @@ Optional:
- `min_tls_version` (String)
- `minify` (Block List, Max: 1) (see [below for nested schema](#nestedblock--settings--minify))
- `mirage` (String)
-- `mobile_redirect` (Block List, Max: 1) (see [below for nested schema](#nestedblock--settings--mobile_redirect))
+- `mobile_redirect` (Block List, Max: 1, Deprecated) (see [below for nested schema](#nestedblock--settings--mobile_redirect))
- `nel` (Block List, Max: 1) (see [below for nested schema](#nestedblock--settings--nel))
- `opportunistic_encryption` (String)
- `opportunistic_onion` (String)
diff --git a/examples/data-sources/cloudflare_gateway_app_types/data-source.tf b/examples/data-sources/cloudflare_gateway_app_types/data-source.tf
new file mode 100644
index 0000000000..7b785ea8cf
--- /dev/null
+++ b/examples/data-sources/cloudflare_gateway_app_types/data-source.tf
@@ -0,0 +1,3 @@
+data "cloudflare_gateway_app_types" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+}
diff --git a/examples/data-sources/cloudflare_gateway_categories/data-source.tf b/examples/data-sources/cloudflare_gateway_categories/data-source.tf
new file mode 100644
index 0000000000..b3eeedfc69
--- /dev/null
+++ b/examples/data-sources/cloudflare_gateway_categories/data-source.tf
@@ -0,0 +1,3 @@
+data "cloudflare_gateway_categories" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+}
diff --git a/examples/data-sources/cloudflare_zone/data-source.tf b/examples/data-sources/cloudflare_zone/data-source.tf
index 531263d33f..cf0b08c748 100644
--- a/examples/data-sources/cloudflare_zone/data-source.tf
+++ b/examples/data-sources/cloudflare_zone/data-source.tf
@@ -5,7 +5,7 @@ data "cloudflare_zone" "example" {
resource "cloudflare_record" "example" {
zone_id = data.cloudflare_zone.example.id
name = "www"
- value = "203.0.113.1"
+ content = "203.0.113.1"
type = "A"
proxied = true
}
diff --git a/examples/resources/cloudflare_access_policy/resource.tf b/examples/resources/cloudflare_access_policy/resource.tf
index 48fc8a4829..24a8c70bae 100644
--- a/examples/resources/cloudflare_access_policy/resource.tf
+++ b/examples/resources/cloudflare_access_policy/resource.tf
@@ -2,7 +2,6 @@
resource "cloudflare_access_policy" "test_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "staging policy"
- precedence = "1"
decision = "allow"
include {
@@ -19,7 +18,6 @@ resource "cloudflare_access_policy" "test_policy" {
resource "cloudflare_access_policy" "test_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "staging policy"
- precedence = "1"
decision = "allow"
include {
diff --git a/examples/resources/cloudflare_cloud_connector_rules/resource.tf b/examples/resources/cloudflare_cloud_connector_rules/resource.tf
new file mode 100644
index 0000000000..4e303070af
--- /dev/null
+++ b/examples/resources/cloudflare_cloud_connector_rules/resource.tf
@@ -0,0 +1,13 @@
+resource "cloudflare_cloud_connector_rules" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+
+ rules {
+ description = "connect aws bucket"
+ enabled = true
+ expression = "http.uri"
+ provider = "aws_s3"
+ parameters {
+ host = "mystorage.s3.ams.amazonaws.com"
+ }
+ }
+}
diff --git a/examples/resources/cloudflare_device_settings_policy/resource.tf b/examples/resources/cloudflare_device_settings_policy/resource.tf
index 762ca0d22b..9abf810271 100644
--- a/examples/resources/cloudflare_device_settings_policy/resource.tf
+++ b/examples/resources/cloudflare_device_settings_policy/resource.tf
@@ -17,4 +17,5 @@ resource "cloudflare_device_settings_policy" "developer_warp_policy" {
service_mode_v2_mode = "warp"
service_mode_v2_port = 3000
exclude_office_ips = false
+ tunnel_protocol = "wireguard"
}
diff --git a/examples/resources/cloudflare_magic_wan_gre_tunnel/import.sh b/examples/resources/cloudflare_magic_wan_gre_tunnel/import.sh
new file mode 100644
index 0000000000..106338e208
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_gre_tunnel/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_magic_wan_gre_tunnel.example /
diff --git a/examples/resources/cloudflare_magic_wan_gre_tunnel/resource.tf b/examples/resources/cloudflare_magic_wan_gre_tunnel/resource.tf
new file mode 100644
index 0000000000..6dbce972e7
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_gre_tunnel/resource.tf
@@ -0,0 +1,13 @@
+resource "cloudflare_magic_wan_gre_tunnel" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GRE_1"
+ customer_gre_endpoint = "203.0.113.1"
+ cloudflare_gre_endpoint = "203.0.113.2"
+ interface_address = "192.0.2.0/31"
+ description = "Tunnel for ISP X"
+ ttl = 64
+ mtu = 1476
+ health_check_enabled = true
+ health_check_target = "203.0.113.1"
+ health_check_type = "reply"
+}
diff --git a/examples/resources/cloudflare_magic_wan_ipsec_tunnel/import.sh b/examples/resources/cloudflare_magic_wan_ipsec_tunnel/import.sh
new file mode 100644
index 0000000000..47324f35fa
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_ipsec_tunnel/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_magic_wan_ipsec_tunnel.example /
diff --git a/examples/resources/cloudflare_magic_wan_ipsec_tunnel/resource.tf b/examples/resources/cloudflare_magic_wan_ipsec_tunnel/resource.tf
new file mode 100644
index 0000000000..266ccf7661
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_ipsec_tunnel/resource.tf
@@ -0,0 +1,13 @@
+resource "cloudflare_magic_wan_ipsec_tunnel" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "IPsec_1"
+ customer_endpoint = "203.0.113.1"
+ cloudflare_endpoint = "203.0.113.1"
+ interface_address = "192.0.2.0/31"
+ description = "Tunnel for ISP X"
+ health_check_enabled = true
+ health_check_target = "203.0.113.1"
+ health_check_type = "reply"
+ psk = "asdf12341234"
+ allow_null_cipher = false
+}
diff --git a/examples/resources/cloudflare_magic_wan_static_route/import.sh b/examples/resources/cloudflare_magic_wan_static_route/import.sh
new file mode 100644
index 0000000000..b2720a91bd
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_static_route/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_magic_wan_static_route.example /
diff --git a/examples/resources/cloudflare_magic_wan_static_route/resource.tf b/examples/resources/cloudflare_magic_wan_static_route/resource.tf
new file mode 100644
index 0000000000..6c326c713d
--- /dev/null
+++ b/examples/resources/cloudflare_magic_wan_static_route/resource.tf
@@ -0,0 +1,14 @@
+resource "cloudflare_magic_wan_static_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ description = "New route for new prefix 192.0.2.0/24"
+ prefix = "192.0.2.0/24"
+ nexthop = "10.0.0.0"
+ priority = 100
+ weight = 10
+ colo_names = [
+ "den01"
+ ]
+ colo_regions = [
+ "APAC"
+ ]
+}
diff --git a/examples/resources/cloudflare_record/resource.tf b/examples/resources/cloudflare_record/resource.tf
index 9b2d26f0b4..4fc2df6736 100644
--- a/examples/resources/cloudflare_record/resource.tf
+++ b/examples/resources/cloudflare_record/resource.tf
@@ -2,7 +2,7 @@
resource "cloudflare_record" "example" {
zone_id = var.cloudflare_zone_id
name = "terraform"
- value = "192.0.2.1"
+ content = "192.0.2.1"
type = "A"
ttl = 3600
}
diff --git a/examples/resources/cloudflare_regional_hostname/resource.tf b/examples/resources/cloudflare_regional_hostname/resource.tf
index ed537f7071..a9db3855b8 100644
--- a/examples/resources/cloudflare_regional_hostname/resource.tf
+++ b/examples/resources/cloudflare_regional_hostname/resource.tf
@@ -3,7 +3,7 @@
resource "cloudflare_record" "example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "example.com"
- value = "192.0.2.1"
+ content = "192.0.2.1"
type = "A"
ttl = 3600
}
diff --git a/examples/resources/cloudflare_split_tunnel/resource.tf b/examples/resources/cloudflare_split_tunnel/resource.tf
index d93c5cdd83..e50d3810fc 100644
--- a/examples/resources/cloudflare_split_tunnel/resource.tf
+++ b/examples/resources/cloudflare_split_tunnel/resource.tf
@@ -22,6 +22,7 @@ resource "cloudflare_split_tunnel" "example_split_tunnel_include" {
resource "cloudflare_device_settings_policy" "developer_warp_policy" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "Developers"
+ description = "Developers WARP settings policy description"
precedence = 10
match = "any(identity.groups.name[*] in {\"Developers\"})"
switch_locked = true
@@ -41,7 +42,7 @@ resource "cloudflare_split_tunnel" "example_device_settings_policy_split_tunnel_
# Including *.example.com in WARP routes for a particular device policy
resource "cloudflare_split_tunnel" "example_split_tunnel_include" {
account_id = "f037e56e89293a057740de681ac9abbe"
- policy_id = cloudflare_device_policy.developer_warp_policy.id
+ policy_id = cloudflare_device_settings_policy.developer_warp_policy.id
mode = "include"
tunnels {
host = "*.example.com"
diff --git a/examples/resources/cloudflare_tunnel_config/resource.tf b/examples/resources/cloudflare_tunnel_config/resource.tf
index dc7312bfcd..d2b3b48baf 100644
--- a/examples/resources/cloudflare_tunnel_config/resource.tf
+++ b/examples/resources/cloudflare_tunnel_config/resource.tf
@@ -1,4 +1,4 @@
-resource "cloudflare_tunnel" "example_tunnel" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example_tunnel" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_tunnel"
secret = "<32 character secret>"
@@ -6,7 +6,7 @@ resource "cloudflare_tunnel" "example_tunnel" {
resource "cloudflare_tunnel_config" "example_config" {
account_id = "f037e56e89293a057740de681ac9abbe"
- tunnel_id = cloudflare_tunnel.example_tunnel.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.example_tunnel.id
config {
warp_routing {
diff --git a/examples/resources/cloudflare_tunnel_route/resource.tf b/examples/resources/cloudflare_tunnel_route/resource.tf
index a7bc85ff4e..27a7b542dd 100644
--- a/examples/resources/cloudflare_tunnel_route/resource.tf
+++ b/examples/resources/cloudflare_tunnel_route/resource.tf
@@ -1,5 +1,5 @@
# Tunnel route
-resource "cloudflare_tunnel_route" "example" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415"
network = "192.0.2.24/32"
@@ -8,15 +8,15 @@ resource "cloudflare_tunnel_route" "example" {
}
# Tunnel with tunnel route
-resource "cloudflare_tunnel" "tunnel" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "tunnel" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "my_tunnel"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-resource "cloudflare_tunnel_route" "example" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
- tunnel_id = cloudflare_tunnel.tunnel.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.tunnel.id
network = "192.0.2.24/32"
comment = "New tunnel route for documentation"
virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
diff --git a/examples/resources/cloudflare_worker_cron_trigger/resource.tf b/examples/resources/cloudflare_worker_cron_trigger/resource.tf
index 306be489b8..fd3dd7f0a5 100644
--- a/examples/resources/cloudflare_worker_cron_trigger/resource.tf
+++ b/examples/resources/cloudflare_worker_cron_trigger/resource.tf
@@ -1,4 +1,4 @@
-resource "cloudflare_worker_script" "example_script" {
+resource "cloudflare_workers_script" "example_script" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example-script"
content = file("path/to/my.js")
@@ -6,7 +6,7 @@ resource "cloudflare_worker_script" "example_script" {
resource "cloudflare_worker_cron_trigger" "example_trigger" {
account_id = "f037e56e89293a057740de681ac9abbe"
- script_name = cloudflare_worker_script.example_script.name
+ script_name = cloudflare_workers_script.example_script.name
schedules = [
"*/5 * * * *", # every 5 minutes
"10 7 * * mon-fri", # 7:10am every weekday
diff --git a/examples/resources/cloudflare_worker_route/resource.tf b/examples/resources/cloudflare_worker_route/resource.tf
index 8bc4f1ad47..b2bef1a13e 100644
--- a/examples/resources/cloudflare_worker_route/resource.tf
+++ b/examples/resources/cloudflare_worker_route/resource.tf
@@ -2,9 +2,9 @@
resource "cloudflare_worker_route" "my_route" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
pattern = "example.com/*"
- script_name = cloudflare_worker_script.my_script.name
+ script_name = cloudflare_workers_script.my_script.name
}
-resource "cloudflare_worker_script" "my_script" {
- # see "cloudflare_worker_script" documentation ...
+resource "cloudflare_workers_script" "my_script" {
+ # see "cloudflare_workers_script" documentation ...
}
diff --git a/examples/resources/cloudflare_workers_cron_trigger/import.sh b/examples/resources/cloudflare_workers_cron_trigger/import.sh
new file mode 100644
index 0000000000..013aa239a8
--- /dev/null
+++ b/examples/resources/cloudflare_workers_cron_trigger/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_cron_trigger.example /
diff --git a/examples/resources/cloudflare_workers_cron_trigger/resource.tf b/examples/resources/cloudflare_workers_cron_trigger/resource.tf
new file mode 100644
index 0000000000..62bfcaaef6
--- /dev/null
+++ b/examples/resources/cloudflare_workers_cron_trigger/resource.tf
@@ -0,0 +1,14 @@
+resource "cloudflare_workers_script" "example_script" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example-script"
+ content = file("path/to/my.js")
+}
+
+resource "cloudflare_workers_cron_trigger" "example_trigger" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ script_name = cloudflare_workers_script.example_script.name
+ schedules = [
+ "*/5 * * * *", # every 5 minutes
+ "10 7 * * mon-fri", # 7:10am every weekday
+ ]
+}
diff --git a/examples/resources/cloudflare_workers_custom_domain/import.sh b/examples/resources/cloudflare_workers_custom_domain/import.sh
new file mode 100644
index 0000000000..e54fb6d250
--- /dev/null
+++ b/examples/resources/cloudflare_workers_custom_domain/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_custom_domain.example /
diff --git a/examples/resources/cloudflare_workers_custom_domain/resource.tf b/examples/resources/cloudflare_workers_custom_domain/resource.tf
new file mode 100644
index 0000000000..14e5ba24c7
--- /dev/null
+++ b/examples/resources/cloudflare_workers_custom_domain/resource.tf
@@ -0,0 +1,6 @@
+resource "cloudflare_workers_custom_domain" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ hostname = "subdomain.example.com"
+ service = "my-service"
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+}
diff --git a/examples/resources/cloudflare_workers_domain/import.sh b/examples/resources/cloudflare_workers_domain/import.sh
new file mode 100644
index 0000000000..504526590b
--- /dev/null
+++ b/examples/resources/cloudflare_workers_domain/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_domain.example /
diff --git a/examples/resources/cloudflare_workers_domain/resource.tf b/examples/resources/cloudflare_workers_domain/resource.tf
new file mode 100644
index 0000000000..ff1a939684
--- /dev/null
+++ b/examples/resources/cloudflare_workers_domain/resource.tf
@@ -0,0 +1,6 @@
+resource "cloudflare_workers_domain" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ hostname = "subdomain.example.com"
+ service = "my-service"
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+}
diff --git a/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/import.sh b/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/import.sh
new file mode 100644
index 0000000000..5d87208a3f
--- /dev/null
+++ b/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_for_platforms_dispatch_namespace.example /
diff --git a/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/resource.tf b/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/resource.tf
new file mode 100644
index 0000000000..08a4d9fcb6
--- /dev/null
+++ b/examples/resources/cloudflare_workers_for_platforms_dispatch_namespace/resource.tf
@@ -0,0 +1,12 @@
+resource "cloudflare_workers_for_platforms_dispatch_namespace" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example-namespace"
+}
+
+resource "cloudflare_workers_script" "customer_worker_1" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "customer-worker-1"
+ content = file("script.js")
+ dispatch_namespace = cloudflare_workers_for_platforms_dispatch_namespace.example.name
+ tags = ["free"]
+}
diff --git a/examples/resources/cloudflare_workers_for_platforms_namespace/resource.tf b/examples/resources/cloudflare_workers_for_platforms_namespace/resource.tf
index 8317c22eac..5ff905d565 100644
--- a/examples/resources/cloudflare_workers_for_platforms_namespace/resource.tf
+++ b/examples/resources/cloudflare_workers_for_platforms_namespace/resource.tf
@@ -3,7 +3,7 @@ resource "cloudflare_workers_for_platforms_namespace" "example" {
name = "example-namespace"
}
-resource "cloudflare_worker_script" "customer_worker_1" {
+resource "cloudflare_workers_script" "customer_worker_1" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "customer-worker-1"
content = file("script.js")
diff --git a/examples/resources/cloudflare_workers_route/import.sh b/examples/resources/cloudflare_workers_route/import.sh
new file mode 100644
index 0000000000..16c5d20e23
--- /dev/null
+++ b/examples/resources/cloudflare_workers_route/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_route.example /
diff --git a/examples/resources/cloudflare_workers_route/resource.tf b/examples/resources/cloudflare_workers_route/resource.tf
new file mode 100644
index 0000000000..f37e29caca
--- /dev/null
+++ b/examples/resources/cloudflare_workers_route/resource.tf
@@ -0,0 +1,10 @@
+# Runs the specified worker script for all URLs that match `example.com/*`
+resource "cloudflare_workers_route" "my_route" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ pattern = "example.com/*"
+ script_name = cloudflare_workers_script.my_script.name
+}
+
+resource "cloudflare_workers_script" "my_script" {
+ # see "cloudflare_workers_script" documentation ...
+}
diff --git a/examples/resources/cloudflare_workers_script/import.sh b/examples/resources/cloudflare_workers_script/import.sh
new file mode 100644
index 0000000000..3789cf2d8b
--- /dev/null
+++ b/examples/resources/cloudflare_workers_script/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_script.example /
diff --git a/examples/resources/cloudflare_workers_script/resource.tf b/examples/resources/cloudflare_workers_script/resource.tf
new file mode 100644
index 0000000000..b15ae74589
--- /dev/null
+++ b/examples/resources/cloudflare_workers_script/resource.tf
@@ -0,0 +1,47 @@
+resource "cloudflare_workers_kv_namespace" "my_namespace" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ title = "example"
+}
+
+# Sets the script with the name "script_1"
+resource "cloudflare_workers_script" "my_script" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "script_1"
+ content = file("script.js")
+
+ kv_namespace_binding {
+ name = "MY_EXAMPLE_KV_NAMESPACE"
+ namespace_id = cloudflare_workers_kv_namespace.my_namespace.id
+ }
+
+ plain_text_binding {
+ name = "MY_EXAMPLE_PLAIN_TEXT"
+ text = "foobar"
+ }
+
+ secret_text_binding {
+ name = "MY_EXAMPLE_SECRET_TEXT"
+ text = var.secret_foo_value
+ }
+
+ webassembly_binding {
+ name = "MY_EXAMPLE_WASM"
+ module = filebase64("example.wasm")
+ }
+
+ service_binding {
+ name = "MY_SERVICE_BINDING"
+ service = "MY_SERVICE"
+ environment = "production"
+ }
+
+ r2_bucket_binding {
+ name = "MY_BUCKET"
+ bucket_name = "MY_BUCKET_NAME"
+ }
+
+ analytics_engine_binding {
+ name = "MY_DATASET"
+ dataset = "dataset1"
+ }
+}
diff --git a/examples/resources/cloudflare_workers_secret/import.sh b/examples/resources/cloudflare_workers_secret/import.sh
new file mode 100644
index 0000000000..75fbf888ce
--- /dev/null
+++ b/examples/resources/cloudflare_workers_secret/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_workers_secret.example //
diff --git a/examples/resources/cloudflare_workers_secret/resource.tf b/examples/resources/cloudflare_workers_secret/resource.tf
new file mode 100644
index 0000000000..60171b7640
--- /dev/null
+++ b/examples/resources/cloudflare_workers_secret/resource.tf
@@ -0,0 +1,6 @@
+resource "cloudflare_workers_secret" "my_secret" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "MY_EXAMPLE_SECRET_TEXT"
+ script_name = "script_1"
+ secret_text = "my_secret_value"
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_application/import.sh b/examples/resources/cloudflare_zero_trust_access_application/import.sh
new file mode 100644
index 0000000000..479dda85a3
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_application/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_access_application.example /
diff --git a/examples/resources/cloudflare_zero_trust_access_application/resource.tf b/examples/resources/cloudflare_zero_trust_access_application/resource.tf
new file mode 100644
index 0000000000..c78fb8160c
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_application/resource.tf
@@ -0,0 +1,31 @@
+resource "cloudflare_zero_trust_access_application" "staging_app" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "staging application"
+ domain = "staging.example.com"
+ type = "self_hosted"
+ session_duration = "24h"
+ auto_redirect_to_identity = false
+ policies = [
+ cloudflare_access_policy.example_1.id,
+ cloudflare_access_policy.example_2.id
+ ]
+}
+
+# With CORS configuration
+resource "cloudflare_zero_trust_access_application" "staging_app" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "staging application"
+ domain = "staging.example.com"
+ type = "self_hosted"
+ session_duration = "24h"
+ policies = [
+ cloudflare_access_policy.example_1.id,
+ cloudflare_access_policy.example_2.id
+ ]
+ cors_headers {
+ allowed_methods = ["GET", "POST", "OPTIONS"]
+ allowed_origins = ["https://example.com"]
+ allow_credentials = true
+ max_age = 10
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_custom_page/resource.tf b/examples/resources/cloudflare_zero_trust_access_custom_page/resource.tf
new file mode 100644
index 0000000000..eb7c54a856
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_custom_page/resource.tf
@@ -0,0 +1,6 @@
+resource "cloudflare_zero_trust_access_custom_page" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "example"
+ type = "forbidden"
+ custom_html = "Forbidden
"
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_group/import.sh b/examples/resources/cloudflare_zero_trust_access_group/import.sh
new file mode 100644
index 0000000000..c1b79b1cc3
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_group/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_access_group.example /
diff --git a/examples/resources/cloudflare_zero_trust_access_group/resource.tf b/examples/resources/cloudflare_zero_trust_access_group/resource.tf
new file mode 100644
index 0000000000..3276df3e45
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_group/resource.tf
@@ -0,0 +1,37 @@
+# Allowing access to `test@example.com` email address only
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging group"
+
+ include {
+ email = ["test@example.com"]
+ }
+}
+
+# Allowing `test@example.com` to access but only when coming from a
+# specific IP.
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging group"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ ip = [var.office_ip]
+ }
+}
+
+# Allow members of an Azure Group. The ID is the group UUID (id) in Azure.
+resource "cloudflare_zero_trust_access_group" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "test_group"
+
+ include {
+ azure {
+ identity_provider_id = "ca298b82-93b5-41bf-bc2d-10493f09b761"
+ id = ["86773093-5feb-48dd-814b-7ccd3676ff50"]
+ }
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_identity_provider/import.sh b/examples/resources/cloudflare_zero_trust_access_identity_provider/import.sh
new file mode 100644
index 0000000000..4756a31742
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_identity_provider/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_access_identity_provider.example /
diff --git a/examples/resources/cloudflare_zero_trust_access_identity_provider/resource.tf b/examples/resources/cloudflare_zero_trust_access_identity_provider/resource.tf
new file mode 100644
index 0000000000..29d218cb77
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_identity_provider/resource.tf
@@ -0,0 +1,44 @@
+# one time pin
+resource "cloudflare_zero_trust_access_identity_provider" "pin_login" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "PIN login"
+ type = "onetimepin"
+}
+
+# oauth
+resource "cloudflare_zero_trust_access_identity_provider" "github_oauth" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GitHub OAuth"
+ type = "github"
+ config {
+ client_id = "example"
+ client_secret = "secret_key"
+ }
+}
+
+# saml
+resource "cloudflare_zero_trust_access_identity_provider" "jumpcloud_saml" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "JumpCloud SAML"
+ type = "saml"
+ config {
+ issuer_url = "jumpcloud"
+ sso_target_url = "https://sso.myexample.jumpcloud.com/saml2/cloudflareaccess"
+ attributes = ["email", "username"]
+ sign_request = false
+ idp_public_cert = "MIIDpDCCAoygAwIBAgIGAV2ka+55MA0GCSqGSIb3DQEBCwUAMIGSMQswCQ...GF/Q2/MHadws97cZg\nuTnQyuOqPuHbnN83d/2l1NSYKCbHt24o"
+ }
+}
+
+# okta
+resource "cloudflare_zero_trust_access_identity_provider" "okta" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Okta"
+ type = "okta"
+ config {
+ client_id = "example"
+ client_secret = "secret_key"
+ api_token = "okta_api_token"
+ okta_account = "https://example.com"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_mtls_certificate/import.sh b/examples/resources/cloudflare_zero_trust_access_mtls_certificate/import.sh
new file mode 100644
index 0000000000..885b1ba312
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_mtls_certificate/import.sh
@@ -0,0 +1,5 @@
+# Account level import.
+$ terraform import cloudflare_zero_sd -t_access_mtls_certificate.example account//
+
+# Zone level import.
+$ terraform import cloudflare_zero_sd -t_access_mtls_certificate.example zone//
diff --git a/examples/resources/cloudflare_zero_trust_access_mtls_certificate/resource.tf b/examples/resources/cloudflare_zero_trust_access_mtls_certificate/resource.tf
new file mode 100644
index 0000000000..850c35e72f
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_mtls_certificate/resource.tf
@@ -0,0 +1,6 @@
+resource "cloudflare_zero_trust_access_mtls_certificate" "my_cert" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ name = "My Root Cert"
+ certificate = var.ca_pem
+ associated_hostnames = ["staging.example.com"]
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/import.sh b/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/import.sh
new file mode 100644
index 0000000000..8082ec2943
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/import.sh
@@ -0,0 +1,5 @@
+# Account level mTLS hostname settings import.
+$ terraform import cloudflare_zero_trust_access_mtls_hostname_settings.example account/
+
+# Zone level mTLS hostname settings import.
+$ terraform import cloudflare_zero_trust_access_mtls_hostname_settings.example zone/
diff --git a/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/resource.tf b/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/resource.tf
new file mode 100644
index 0000000000..69d9ed799b
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_mtls_hostname_settings/resource.tf
@@ -0,0 +1,8 @@
+resource "cloudflare_zero_trust_access_mtls_hostname_settings" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ settings {
+ hostname = "example.com"
+ client_certificate_forwarding = true
+ china_network = false
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_policy/import.sh b/examples/resources/cloudflare_zero_trust_access_policy/import.sh
new file mode 100644
index 0000000000..a0c41f229a
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_policy/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_access_policy.example account///
diff --git a/examples/resources/cloudflare_zero_trust_access_policy/resource.tf b/examples/resources/cloudflare_zero_trust_access_policy/resource.tf
new file mode 100644
index 0000000000..08f6477bdd
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_policy/resource.tf
@@ -0,0 +1,30 @@
+# Allowing access to `test@example.com` email address only
+resource "cloudflare_zero_trust_access_policy" "test_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging policy"
+ decision = "allow"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ email = ["test@example.com"]
+ }
+}
+
+# Allowing `test@example.com` to access but only when coming from a
+# specific IP.
+resource "cloudflare_zero_trust_access_policy" "test_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "staging policy"
+ decision = "allow"
+
+ include {
+ email = ["test@example.com"]
+ }
+
+ require {
+ ip = [var.office_ip]
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_service_token/import.sh b/examples/resources/cloudflare_zero_trust_access_service_token/import.sh
new file mode 100644
index 0000000000..a5e320c404
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_service_token/import.sh
@@ -0,0 +1,5 @@
+# If you are importing an Access Service Token you will not have the
+# client_secret available in the state for use. The client_secret is only
+# available once, at creation. In most cases, it is better to just create a new
+# resource should you need to reference it in other resources.
+$ terraform import cloudflare_zero_trust_access_service_token.example /
diff --git a/examples/resources/cloudflare_zero_trust_access_service_token/resource.tf b/examples/resources/cloudflare_zero_trust_access_service_token/resource.tf
new file mode 100644
index 0000000000..4c1ee57589
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_service_token/resource.tf
@@ -0,0 +1,19 @@
+resource "cloudflare_zero_trust_access_service_token" "my_app" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "CI/CD app"
+}
+
+# Generate a service token that will renew if terraform is ran within 30 days of expiration
+resource "cloudflare_zero_trust_access_service_token" "my_app" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "CI/CD app renewed"
+
+ min_days_for_renewal = 30
+
+ # This flag is important to set if min_days_for_renewal is defined otherwise
+ # there will be a brief period where the service relying on that token
+ # will not have access due to the resource being deleted
+ lifecycle {
+ create_before_destroy = true
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/import.sh b/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/import.sh
new file mode 100644
index 0000000000..4403b429d5
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/import.sh
@@ -0,0 +1,5 @@
+# Account level CA certificate import.
+$ terraform import cloudflare_zero_trust_access_short_lived_certificate.example account//
+
+# Zone level CA certificate import.
+$ terraform import cloudflare_zero_trust_access_short_lived_certificate.example account//
diff --git a/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/resource.tf b/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/resource.tf
new file mode 100644
index 0000000000..acafb6afc8
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_access_short_lived_certificate/resource.tf
@@ -0,0 +1,11 @@
+# account level
+resource "cloudflare_zero_trust_access_short_lived_certificate" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ application_id = "6cd6cea3-3ef2-4542-9aea-85a0bbcd5414"
+}
+
+# zone level
+resource "cloudflare_zero_trust_access_short_lived_certificate" "another_example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ application_id = "fe2be0ff-7f13-4350-8c8e-a9b9795fe3c2"
+}
diff --git a/examples/resources/cloudflare_zero_trust_device_certificates/import.sh b/examples/resources/cloudflare_zero_trust_device_certificates/import.sh
new file mode 100644
index 0000000000..9198d45c57
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_certificates/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_device_certificates.example
diff --git a/examples/resources/cloudflare_zero_trust_device_certificates/resource.tf b/examples/resources/cloudflare_zero_trust_device_certificates/resource.tf
new file mode 100644
index 0000000000..0594740d91
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_certificates/resource.tf
@@ -0,0 +1,4 @@
+resource "cloudflare_zero_trust_device_certificates" "example" {
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
+ enabled = true
+}
diff --git a/examples/resources/cloudflare_zero_trust_device_managed_networks/import.sh b/examples/resources/cloudflare_zero_trust_device_managed_networks/import.sh
new file mode 100644
index 0000000000..cb6e46945a
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_managed_networks/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_device_managed_networks.example /
diff --git a/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf b/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf
new file mode 100644
index 0000000000..93a412413f
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf
@@ -0,0 +1,9 @@
+resource "cloudflare_zero_trust_device_managed_networks" "managed_networks" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "managed-network-1"
+ type = "tls"
+ config {
+ tls_sockaddr = "foobar:1234"
+ sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_device_posture_integration/import.sh b/examples/resources/cloudflare_zero_trust_device_posture_integration/import.sh
new file mode 100644
index 0000000000..b39b454003
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_posture_integration/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_device_posture_integration.example /
diff --git a/examples/resources/cloudflare_zero_trust_device_posture_integration/resource.tf b/examples/resources/cloudflare_zero_trust_device_posture_integration/resource.tf
new file mode 100644
index 0000000000..499af39988
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_posture_integration/resource.tf
@@ -0,0 +1,12 @@
+resource "cloudflare_zero_trust_device_posture_integration" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Device posture integration"
+ type = "workspace_one"
+ interval = "24h"
+ config {
+ api_url = "https://example.com/api"
+ auth_url = "https://example.com/connect/token"
+ client_id = "client-id"
+ client_secret = "client-secret"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_device_posture_rule/import.sh b/examples/resources/cloudflare_zero_trust_device_posture_rule/import.sh
new file mode 100644
index 0000000000..229420a443
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_posture_rule/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_device_posture_rule.example /
diff --git a/examples/resources/cloudflare_zero_trust_device_posture_rule/resource.tf b/examples/resources/cloudflare_zero_trust_device_posture_rule/resource.tf
new file mode 100644
index 0000000000..c20a55b68c
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_posture_rule/resource.tf
@@ -0,0 +1,21 @@
+resource "cloudflare_zero_trust_device_posture_rule" "eaxmple" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Corporate devices posture rule"
+ type = "os_version"
+ description = "Device posture rule for corporate devices."
+ schedule = "24h"
+ expiration = "24h"
+
+ match {
+ platform = "linux"
+ }
+
+ input {
+ id = cloudflare_teams_list.corporate_devices.id
+ version = "1.0.0"
+ operator = "<"
+ os_distro_name = "ubuntu"
+ os_distro_revision = "1.0.0"
+ os_version_extra = "(a)"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_device_profiles/import.sh b/examples/resources/cloudflare_zero_trust_device_profiles/import.sh
new file mode 100644
index 0000000000..6e5de06d2f
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_profiles/import.sh
@@ -0,0 +1,2 @@
+# For default device settings policies you must use "default" as the policy ID.
+$ terraform import cloudflare_zero_trust_device_profiles.example /
diff --git a/examples/resources/cloudflare_zero_trust_device_profiles/resource.tf b/examples/resources/cloudflare_zero_trust_device_profiles/resource.tf
new file mode 100644
index 0000000000..f471a9d22a
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_device_profiles/resource.tf
@@ -0,0 +1,20 @@
+resource "cloudflare_zero_trust_device_profiles" "developer_warp_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Developers WARP settings policy"
+ description = "Developers WARP settings policy description"
+ precedence = 10
+ match = "any(identity.groups.name[*] in {\"Developers\"})"
+ default = false
+ enabled = true
+ allow_mode_switch = true
+ allow_updates = true
+ allowed_to_leave = true
+ auto_connect = 0
+ captive_portal = 5
+ disable_auto_fallback = true
+ support_url = "https://cloudflare.com"
+ switch_locked = true
+ service_mode_v2_mode = "warp"
+ service_mode_v2_port = 3000
+ exclude_office_ips = false
+}
diff --git a/examples/resources/cloudflare_zero_trust_dex_test/import.sh b/examples/resources/cloudflare_zero_trust_dex_test/import.sh
new file mode 100644
index 0000000000..03ecb90c89
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dex_test/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_dex_test.example /
\ No newline at end of file
diff --git a/examples/resources/cloudflare_zero_trust_dex_test/resource.tf b/examples/resources/cloudflare_zero_trust_dex_test/resource.tf
new file mode 100644
index 0000000000..7ee9dca338
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dex_test/resource.tf
@@ -0,0 +1,12 @@
+resource "cloudflare_zero_trust_dex_test" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "GET homepage"
+ description = "Send a HTTP GET request to the home endpoint every half hour."
+ interval = "0h30m0s"
+ enabled = true
+ data {
+ host = "https://example.com/home"
+ kind = "http"
+ method = "GET"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_dlp_profile/import.sh b/examples/resources/cloudflare_zero_trust_dlp_profile/import.sh
new file mode 100644
index 0000000000..08c3c6a3bf
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dlp_profile/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_dlp_profile.example /
diff --git a/examples/resources/cloudflare_zero_trust_dlp_profile/resource.tf b/examples/resources/cloudflare_zero_trust_dlp_profile/resource.tf
new file mode 100644
index 0000000000..58d06f9cb5
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dlp_profile/resource.tf
@@ -0,0 +1,60 @@
+# Predefined profile must be imported, cannot be created
+resource "cloudflare_zero_trust_dlp_profile" "creds" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Credentials and Secrets"
+ type = "predefined"
+ allowed_match_count = 3
+
+ entry {
+ enabled = true
+ name = "Amazon AWS Access Key ID"
+ id = "d8fcfc9c-773c-405e-8426-21ecbb67ba93"
+ }
+ entry {
+ enabled = false
+ id = "2c0e33e1-71da-40c8-aad3-32e674ad3d96"
+ name = "Amazon AWS Secret Access Key"
+ }
+ entry {
+ enabled = true
+ id = "4e92c006-3802-4dff-bbe1-8e1513b1c92a"
+ name = "Microsoft Azure Client Secret"
+ }
+ entry {
+ enabled = false
+ id = "5c713294-2375-4904-abcf-e4a15be4d592"
+ name = "SSH Private Key"
+ }
+ entry {
+ enabled = true
+ id = "6c6579e4-d832-42d5-905c-8e53340930f2"
+ name = "Google GCP API Key"
+ }
+}
+
+# Custom profile
+resource "cloudflare_zero_trust_dlp_profile" "example_custom" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Example Custom Profile"
+ description = "A profile with example entries"
+ type = "custom"
+ allowed_match_count = 0
+
+ entry {
+ name = "Matches visa credit cards"
+ enabled = true
+ pattern {
+ regex = "4\\d{3}([-\\. ])?\\d{4}([-\\. ])?\\d{4}([-\\. ])?\\d{4}"
+ validation = "luhn"
+ }
+ }
+
+ entry {
+ name = "Matches diners club card"
+ enabled = true
+ pattern {
+ regex = "(?:0[0-5]|[68][0-9])[0-9]{11}"
+ validation = "luhn"
+ }
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_dns_location/import.sh b/examples/resources/cloudflare_zero_trust_dns_location/import.sh
new file mode 100644
index 0000000000..3e6f3e90dd
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dns_location/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_dns_location.example /
diff --git a/examples/resources/cloudflare_zero_trust_dns_location/resource.tf b/examples/resources/cloudflare_zero_trust_dns_location/resource.tf
new file mode 100644
index 0000000000..d3051cf53a
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_dns_location/resource.tf
@@ -0,0 +1,14 @@
+resource "cloudflare_zero_trust_dns_location" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ client_default = true
+ ecs_support = false
+
+ networks {
+ network = "203.0.113.1/32"
+ }
+
+ networks {
+ network = "203.0.113.2/32"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_gateway_policy/import.sh b/examples/resources/cloudflare_zero_trust_gateway_policy/import.sh
new file mode 100644
index 0000000000..701e364636
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_policy/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_gateway_policy.example /
diff --git a/examples/resources/cloudflare_zero_trust_gateway_policy/resource.tf b/examples/resources/cloudflare_zero_trust_gateway_policy/resource.tf
new file mode 100644
index 0000000000..3309f3d21b
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_policy/resource.tf
@@ -0,0 +1,13 @@
+resource "cloudflare_zero_trust_gateway_policy" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ description = "desc"
+ precedence = 1
+ action = "block"
+ filters = ["http"]
+ traffic = "http.request.uri == \"https://www.example.com/malicious\""
+ rule_settings {
+ block_page_enabled = true
+ block_page_reason = "access not permitted"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/import.sh b/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/import.sh
new file mode 100644
index 0000000000..f999ebf0e3
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_gateway_proxy_endpoint.example /
diff --git a/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/resource.tf b/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/resource.tf
new file mode 100644
index 0000000000..bde5b1e6d9
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_proxy_endpoint/resource.tf
@@ -0,0 +1,5 @@
+resource "cloudflare_zero_trust_gateway_proxy_endpoint" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "office"
+ ips = ["192.0.2.0/24"]
+}
diff --git a/examples/resources/cloudflare_zero_trust_gateway_settings/import.sh b/examples/resources/cloudflare_zero_trust_gateway_settings/import.sh
new file mode 100644
index 0000000000..f3b5456547
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_settings/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_gateway_settings.example
diff --git a/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf b/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf
new file mode 100644
index 0000000000..6c9f34e136
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf
@@ -0,0 +1,62 @@
+resource "cloudflare_zero_trust_gateway_settings" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tls_decrypt_enabled = true
+ protocol_detection_enabled = true
+
+ block_page {
+ footer_text = "hello"
+ header_text = "hello"
+ logo_path = "https://example.com/logo.jpg"
+ background_color = "#000000"
+ }
+
+ body_scanning {
+ inspection_mode = "deep"
+ }
+
+ antivirus {
+ enabled_download_phase = true
+ enabled_upload_phase = false
+ fail_closed = true
+ notification_settings {
+ enabled = true
+ message = "you are blocked"
+ support_url = "https://example.com/blocked"
+ }
+ }
+
+ fips {
+ tls = true
+ }
+
+ proxy {
+ tcp = true
+ udp = true
+ root_ca = true
+ virtual_ip = false
+ }
+
+ url_browser_isolation_enabled = true
+
+ logging {
+ redact_pii = true
+ settings_by_rule_type {
+ dns {
+ log_all = false
+ log_blocks = true
+ }
+ http {
+ log_all = true
+ log_blocks = true
+ }
+ l4 {
+ log_all = false
+ log_blocks = true
+ }
+ }
+ }
+
+ extended_email_matching {
+ enabled = true
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_list/import.sh b/examples/resources/cloudflare_zero_trust_list/import.sh
new file mode 100644
index 0000000000..7bfba37a1c
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_list/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_list.example /
diff --git a/examples/resources/cloudflare_zero_trust_list/resource.tf b/examples/resources/cloudflare_zero_trust_list/resource.tf
new file mode 100644
index 0000000000..8a1c45e7e7
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_list/resource.tf
@@ -0,0 +1,7 @@
+resource "cloudflare_zero_trust_list" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Corporate devices"
+ type = "SERIAL"
+ description = "Serial numbers for all corporate devices."
+ items = ["8GE8721REF", "5RE8543EGG", "1YE2880LNP"]
+}
diff --git a/examples/resources/cloudflare_zero_trust_local_domain_fallback/import.sh b/examples/resources/cloudflare_zero_trust_local_domain_fallback/import.sh
new file mode 100644
index 0000000000..74f62d1347
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_local_domain_fallback/import.sh
@@ -0,0 +1,2 @@
+# Fallback Domains for default device policies must use "default" as the policy ID.
+$ terraform import cloudflare_zero_trust_local_domain_fallback.example /
diff --git a/examples/resources/cloudflare_zero_trust_local_domain_fallback/resource.tf b/examples/resources/cloudflare_zero_trust_local_domain_fallback/resource.tf
new file mode 100644
index 0000000000..3559e55f38
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_local_domain_fallback/resource.tf
@@ -0,0 +1,46 @@
+# Use DNS servers 192.0.2.0 or 192.0.2.1 for example.com
+resource "cloudflare_zero_trust_local_domain_fallback" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ domains {
+ suffix = "example.com"
+ description = "Example domain"
+ dns_server = ["192.0.2.0", "192.0.2.1"]
+ }
+}
+
+# Explicitly adding example.com to the default entries.
+resource "cloudflare_zero_trust_local_domain_fallback" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ dynamic "domains" {
+ for_each = toset(["intranet", "internal", "private", "localdomain", "domain", "lan", "home", "host", "corp", "local", "localhost", "home.arpa", "invalid", "test"])
+ content {
+ suffix = domains.value
+ }
+ }
+
+ domains {
+ suffix = "example.com"
+ description = "Example domain"
+ dns_server = ["192.0.2.0", "192.0.2.1"]
+ }
+}
+
+# Create a device policy
+resource "cloudflare_device_settings_policy" "developer_warp_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Developers"
+ precedence = 10
+ match = "any(identity.groups.name[*] in {\"Developers\"})"
+ switch_locked = true
+}
+
+# Use DNS servers 192.0.2.0 or 192.0.2.1 for example.com for a particular device policy
+resource "cloudflare_zero_trust_local_domain_fallback" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ policy_id = cloudflare_device_settings_policy.developer_warp_policy.id
+ domains {
+ suffix = "example.com"
+ description = "Example domain"
+ dns_server = ["192.0.2.0", "192.0.2.1"]
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_organization/import.sh b/examples/resources/cloudflare_zero_trust_organization/import.sh
new file mode 100644
index 0000000000..707472ec57
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_organization/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_organization.example
diff --git a/examples/resources/cloudflare_zero_trust_organization/resource.tf b/examples/resources/cloudflare_zero_trust_organization/resource.tf
new file mode 100644
index 0000000000..ea73b15cbb
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_organization/resource.tf
@@ -0,0 +1,16 @@
+resource "cloudflare_zero_trust_organization" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example.cloudflareaccess.com"
+ auth_domain = "example.cloudflareaccess.com"
+ is_ui_read_only = false
+ user_seat_expiration_inactive_time = "720h"
+ auto_redirect_to_identity = false
+
+ login_design {
+ background_color = "#ffffff"
+ text_color = "#000000"
+ logo_path = "https://example.com/logo.png"
+ header_text = "My header text"
+ footer_text = "My footer text"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_split_tunnels/import.sh b/examples/resources/cloudflare_zero_trust_split_tunnels/import.sh
new file mode 100644
index 0000000000..f5dac094ac
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_split_tunnels/import.sh
@@ -0,0 +1,2 @@
+# Split Tunnels for default device policies must use "default" as the policy ID.
+$ terraform import cloudflare_zero_trust_split_tunnels.example //
diff --git a/examples/resources/cloudflare_zero_trust_split_tunnels/resource.tf b/examples/resources/cloudflare_zero_trust_split_tunnels/resource.tf
new file mode 100644
index 0000000000..8d90af9c3a
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_split_tunnels/resource.tf
@@ -0,0 +1,51 @@
+# Excluding *.example.com from WARP routes
+resource "cloudflare_zero_trust_split_tunnels" "example_split_tunnel_exclude" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ mode = "exclude"
+ tunnels {
+ host = "*.example.com"
+ description = "example domain"
+ }
+}
+
+# Including *.example.com in WARP routes
+resource "cloudflare_zero_trust_split_tunnels" "example_split_tunnel_include" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ mode = "include"
+ tunnels {
+ host = "*.example.com"
+ description = "example domain"
+ }
+}
+
+# Create a device policy
+resource "cloudflare_device_settings_policy" "developer_warp_policy" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "Developers"
+ description = "Developers WARP settings policy description"
+ precedence = 10
+ match = "any(identity.groups.name[*] in {\"Developers\"})"
+ switch_locked = true
+}
+
+# Excluding *.example.com from WARP routes for a particular device policy
+resource "cloudflare_zero_trust_split_tunnels" "example_device_settings_policy_split_tunnel_exclude" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ policy_id = cloudflare_device_settings_policy.developer_warp_policy.id
+ mode = "exclude"
+ tunnels {
+ host = "*.example.com"
+ description = "example domain"
+ }
+}
+
+# Including *.example.com in WARP routes for a particular device policy
+resource "cloudflare_zero_trust_split_tunnels" "example_split_tunnel_include" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ policy_id = cloudflare_device_settings_policy.developer_warp_policy.id
+ mode = "include"
+ tunnels {
+ host = "*.example.com"
+ description = "example domain"
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/import.sh
new file mode 100644
index 0000000000..4ab1443f16
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_tunnel_cloudflared.example /
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/resource.tf b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/resource.tf
new file mode 100644
index 0000000000..5c1f295bab
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared/resource.tf
@@ -0,0 +1,5 @@
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "my-tunnel"
+ secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
+}
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/import.sh
new file mode 100644
index 0000000000..029c329fcc
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_tunnel_cloudflared_config.example /
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/resource.tf b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/resource.tf
new file mode 100644
index 0000000000..009f10de29
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_cloudflared_config/resource.tf
@@ -0,0 +1,54 @@
+resource "cloudflare_zero_trust_tunnel_cloudflared" "example_tunnel" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "example_tunnel"
+ secret = "<32 character secret>"
+}
+
+resource "cloudflare_zero_trust_tunnel_cloudflared_config" "example_config" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.example_tunnel.id
+
+ config {
+ warp_routing {
+ enabled = true
+ }
+ origin_request {
+ connect_timeout = "1m0s"
+ tls_timeout = "1m0s"
+ tcp_keep_alive = "1m0s"
+ no_happy_eyeballs = false
+ keep_alive_connections = 1024
+ keep_alive_timeout = "1m0s"
+ http_host_header = "baz"
+ origin_server_name = "foobar"
+ ca_pool = "/path/to/unsigned/ca/pool"
+ no_tls_verify = false
+ disable_chunked_encoding = false
+ bastion_mode = false
+ proxy_address = "10.0.0.1"
+ proxy_port = "8123"
+ proxy_type = "socks"
+ ip_rules {
+ prefix = "/web"
+ ports = [80, 443]
+ allow = false
+ }
+ }
+ ingress_rule {
+ hostname = "foo"
+ path = "/bar"
+ service = "http://10.0.0.2:8080"
+ origin_request {
+ connect_timeout = "2m0s"
+ access {
+ required = true
+ team_name = "terraform"
+ aud_tag = ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
+ }
+ }
+ }
+ ingress_rule {
+ service = "https://10.0.0.3:8081"
+ }
+ }
+}
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_route/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_route/import.sh
new file mode 100644
index 0000000000..1e3c083a72
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_route/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_tunnel_route.example //
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_route/resource.tf b/examples/resources/cloudflare_zero_trust_tunnel_route/resource.tf
new file mode 100644
index 0000000000..d22ff96542
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_route/resource.tf
@@ -0,0 +1,23 @@
+# Tunnel route
+resource "cloudflare_zero_trust_tunnel_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415"
+ network = "192.0.2.24/32"
+ comment = "New tunnel route for documentation"
+ virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
+}
+
+# Tunnel with tunnel route
+resource "cloudflare_zero_trust_tunnel_cloudflared" "tunnel" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "my_tunnel"
+ secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
+}
+
+resource "cloudflare_zero_trust_tunnel_route" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.tunnel.id
+ network = "192.0.2.24/32"
+ comment = "New tunnel route for documentation"
+ virtual_network_id = "bdc39a3c-3104-4c23-8ac0-9f455dda691a"
+}
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/import.sh
new file mode 100644
index 0000000000..46f9c84e27
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/import.sh
@@ -0,0 +1 @@
+$ terraform import cloudflare_zero_trust_tunnel_virtual_network.example /
diff --git a/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/resource.tf b/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/resource.tf
new file mode 100644
index 0000000000..8902165b37
--- /dev/null
+++ b/examples/resources/cloudflare_zero_trust_tunnel_virtual_network/resource.tf
@@ -0,0 +1,5 @@
+resource "cloudflare_zero_trust_tunnel_virtual_network" "example" {
+ account_id = "f037e56e89293a057740de681ac9abbe"
+ name = "vnet-for-documentation"
+ comment = "New tunnel virtual network for documentation"
+}
\ No newline at end of file
diff --git a/examples/resources/cloudflare_zone_settings_override/resource.tf b/examples/resources/cloudflare_zone_settings_override/resource.tf
index dfcec4420c..ca39b05f4c 100644
--- a/examples/resources/cloudflare_zone_settings_override/resource.tf
+++ b/examples/resources/cloudflare_zone_settings_override/resource.tf
@@ -1,5 +1,5 @@
resource "cloudflare_zone_settings_override" "test" {
- zone_id = d41d8cd98f00b204e9800998ecf8427e
+ zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
settings {
brotli = "on"
challenge_ttl = 2700
diff --git a/go.mod b/go.mod
index 4c6fac8b9b..ca37aa9a56 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.21
require (
github.com/agext/levenshtein v1.2.3 // indirect
- github.com/cloudflare/cloudflare-go v0.97.0
+ github.com/cloudflare/cloudflare-go v0.101.0
github.com/fatih/color v1.16.0 // indirect
github.com/google/uuid v1.6.0
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -13,7 +13,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.6.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
- github.com/hashicorp/hcl/v2 v2.20.1 // indirect
+ github.com/hashicorp/hcl/v2 v2.21.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.23.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/hashicorp/yamux v0.1.1 // indirect
@@ -23,48 +23,48 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pkg/errors v0.9.1
- github.com/zclconf/go-cty v1.14.4 // indirect
- golang.org/x/crypto v0.24.0 // indirect
- golang.org/x/net v0.26.0
- golang.org/x/sys v0.21.0 // indirect
- golang.org/x/text v0.16.0 // indirect
+ github.com/zclconf/go-cty v1.15.0 // indirect
+ golang.org/x/crypto v0.26.0 // indirect
+ golang.org/x/net v0.28.0
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
)
require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
- github.com/aws/aws-sdk-go-v2 v1.27.2
- github.com/aws/aws-sdk-go-v2/config v1.27.18
- github.com/aws/aws-sdk-go-v2/credentials v1.17.18
- github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1
- github.com/cloudflare/cloudflare-go/v2 v2.2.0
+ github.com/aws/aws-sdk-go-v2 v1.30.3
+ github.com/aws/aws-sdk-go-v2/config v1.27.27
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.27
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3
+ github.com/cloudflare/cloudflare-go/v2 v2.4.0
github.com/google/go-cmp v0.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
- github.com/hashicorp/terraform-plugin-framework v1.9.0
- github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
+ github.com/hashicorp/terraform-plugin-framework v1.11.0
+ github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.16.0
- github.com/hashicorp/terraform-plugin-testing v1.8.0
+ github.com/hashicorp/terraform-plugin-testing v1.10.0
github.com/stretchr/testify v1.9.0
)
require (
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
- github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
- github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect
- github.com/aws/smithy-go v1.20.2 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
+ github.com/aws/smithy-go v1.20.3 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
@@ -72,8 +72,8 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
- github.com/hashicorp/go-version v1.6.0 // indirect
- github.com/hashicorp/hc-install v0.6.4 // indirect
+ github.com/hashicorp/go-version v1.7.0 // indirect
+ github.com/hashicorp/hc-install v0.8.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.21.0 // indirect
github.com/hashicorp/terraform-json v0.22.1 // indirect
@@ -92,8 +92,8 @@ require (
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/mod v0.19.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
diff --git a/go.sum b/go.sum
index 73d185397c..002fef70af 100644
--- a/go.sum
+++ b/go.sum
@@ -11,50 +11,50 @@ github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
-github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8=
-github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
-github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk=
-github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw=
+github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
+github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
+github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
+github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 h1:vHyZxoLVOgrI8GqX7OMHLXp4YYoxeEsrjweXKpye+ds=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9/go.mod h1:z9VXZsWA2BvZNH1dT0ToUYwMu/CR9Skkj/TBX+mceZw=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 h1:4vt9Sspk59EZyHCAEMaktHKiq0C09noRTQorXD/qV+s=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11/go.mod h1:5jHR79Tv+Ccq6rwYh+W7Nptmw++WiFafMfR42XhwNl8=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 h1:TE2i0A9ErH1YfRSvXfCr2SQwfnqsoJT9nPQ9kj0lkxM=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9/go.mod h1:9TzXX3MehQNGPwCZ3ka4CpwQsoAMWSF48/b+De9rfVM=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 h1:UAxBuh0/8sFJk1qOkvOKewP5sWeWaTPDknbQz0ZkDm0=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1/go.mod h1:hWjsYGjVuqCgfoveVcVFPXIWgz0aByzwaxKlN1StKcM=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw=
-github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
-github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
-github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
+github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
+github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cloudflare/cloudflare-go v0.97.0 h1:feZRGiRF1EbljnNIYdt8014FnOLtC3CCvgkLXu915ks=
-github.com/cloudflare/cloudflare-go v0.97.0/go.mod h1:JXRwuTfHpe5xFg8xytc2w0XC6LcrFsBVMS4WlVaiGg8=
-github.com/cloudflare/cloudflare-go/v2 v2.2.0 h1:ZUKQDfJ3brCrTSxHvcY7KiFjwYmSj2KwInXQkl2w1QQ=
-github.com/cloudflare/cloudflare-go/v2 v2.2.0/go.mod h1:AoIzb05z/rvdJLztPct4tSa+3IqXJJ6c+pbUFMOlTr8=
+github.com/cloudflare/cloudflare-go v0.101.0 h1:SXWNSEDkbdY84iFIZGyTdWQwDfd98ljv0/4UubpleBQ=
+github.com/cloudflare/cloudflare-go v0.101.0/go.mod h1:xXQHnoXKR48JlWbFS42i2al3nVqimVhcYvKnIdXLw9g=
+github.com/cloudflare/cloudflare-go/v2 v2.4.0 h1:gys/26GoVDklgfq8NYV39WgvOEwzK/XAqYObmnI6iFg=
+github.com/cloudflare/cloudflare-go/v2 v2.4.0/go.mod h1:AoIzb05z/rvdJLztPct4tSa+3IqXJJ6c+pbUFMOlTr8=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@@ -113,22 +113,22 @@ github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFO
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
-github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hc-install v0.6.4 h1:QLqlM56/+SIIGvGcfFiwMY3z5WGXT066suo/v9Km8e0=
-github.com/hashicorp/hc-install v0.6.4/go.mod h1:05LWLy8TD842OtgcfBbOT0WMoInBMUSHjmDx10zuBIA=
-github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc=
-github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1CdfOLjI=
+github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU=
+github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
+github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
-github.com/hashicorp/terraform-plugin-framework v1.9.0 h1:caLcDoxiRucNi2hk8+j3kJwkKfvHznubyFsJMWfZqKU=
-github.com/hashicorp/terraform-plugin-framework v1.9.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
-github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
-github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
+github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
+github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
+github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 h1:bxZfGo9DIUoLLtHMElsu+zwqI4IsMZQBRRy4iLzZJ8E=
+github.com/hashicorp/terraform-plugin-framework-validators v0.13.0/go.mod h1:wGeI02gEhj9nPANU62F2jCaHjXulejm/X+af4PdZaNo=
github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
@@ -137,8 +137,8 @@ github.com/hashicorp/terraform-plugin-mux v0.16.0 h1:RCzXHGDYwUwwqfYYWJKBFaS3fQs
github.com/hashicorp/terraform-plugin-mux v0.16.0/go.mod h1:PF79mAsPc8CpusXPfEVa4X8PtkB+ngWoiUClMrNZlYo=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
-github.com/hashicorp/terraform-plugin-testing v1.8.0 h1:wdYIgwDk4iO933gC4S8KbKdnMQShu6BXuZQPScmHvpk=
-github.com/hashicorp/terraform-plugin-testing v1.8.0/go.mod h1:o2kOgf18ADUaZGhtOl0YCkfIxg01MAiMATT2EtIHlZk=
+github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw=
+github.com/hashicorp/terraform-plugin-testing v1.10.0/go.mod h1:iWRW3+loP33WMch2P/TEyCxxct/ZEcCGMquSLSCVsrc=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
@@ -215,28 +215,28 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
-github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
-github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
-github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
+github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
+github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -249,19 +249,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go
index f711f21c6f..aad9e4ea31 100644
--- a/internal/acctest/acctest.go
+++ b/internal/acctest/acctest.go
@@ -50,9 +50,9 @@ var TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServe
}
func TestAccPreCheck(t *testing.T) {
- // You can add code here to run prior to any test case execution, for example assertions
- // about the appropriate environment variables being set are common to see in a pre-check
- // function.
+ if os.Getenv("CLOUDFLARE_ACCOUNT_ID") == "" {
+ t.Fatal("CLOUDFLARE_ACCOUNT_ID must be set for acceptance tests")
+ }
}
func TestAccPreCheck_Zone(t *testing.T) {
@@ -67,6 +67,40 @@ func TestAccPreCheck_Account(t *testing.T) {
// function.
}
+func TestAccPreCheck_Hyperdrive(t *testing.T) {
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME must be set for this acceptance test")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME must be set for this acceptance test")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PORT"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_DATABASE_PORT must be set for this acceptance test")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_USER"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_DATABASE_USER must be set for this acceptance test")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD must be set for this acceptance test")
+ }
+}
+
+func TestAccPreCheck_HyperdriveWithAccess(t *testing.T) {
+ TestAccPreCheck_Hyperdrive(t)
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_ID"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_ID must be set for this acceptance test")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_SECRET"); v == "" {
+ t.Fatal("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_SECRET must be set for this acceptance test")
+ }
+}
+
func TestAccSkipForDefaultZone(t *testing.T, reason string) {
if os.Getenv("CLOUDFLARE_ZONE_ID") == testAccCloudflareZoneID {
t.Skipf("Skipping acceptance test for default zone (%s). %s", testAccCloudflareZoneID, reason)
diff --git a/internal/framework/provider/provider.go b/internal/framework/provider/provider.go
index d2ba5db2af..f7f49679c3 100644
--- a/internal/framework/provider/provider.go
+++ b/internal/framework/provider/provider.go
@@ -7,6 +7,7 @@ import (
"math"
"regexp"
"strconv"
+ "strings"
"testing"
cfv1 "github.com/cloudflare/cloudflare-go"
@@ -16,10 +17,13 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/access_mutual_tls_hostname_settings"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/api_token_permissions_groups"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/cloud_connector_rules"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/d1"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/dlp_datasets"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/email_routing_address"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/email_routing_rule"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/gateway_app_types"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/gateway_categories"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/hyperdrive_config"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/list_item"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/origin_ca_certificate"
@@ -28,7 +32,11 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/rulesets"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/turnstile"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/user"
- "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/workers_for_platforms"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/workers_for_platforms_dispatch_namespace"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/workers_for_platforms_dispatch_namespace_deprecated"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/zero_trust_access_mtls_hostname_settings"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/zero_trust_risk_behavior"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/zero_trust_risk_score_integration"
"github.com/cloudflare/terraform-provider-cloudflare/internal/sdkv2provider"
"github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
@@ -194,8 +202,12 @@ func (p *CloudflareProvider) Configure(ctx context.Context, req provider.Configu
} else {
basePath = utils.GetDefaultFromEnv(consts.APIBasePathEnvVarKey, consts.APIBasePathDefault)
}
+
baseURL := cfv1.BaseURL(fmt.Sprintf("https://%s%s", baseHostname, basePath))
- cfv2Options = append(cfv2Options, option.WithBaseURL(fmt.Sprintf("https://%s%s", baseHostname, basePath)))
+
+ // Ensure there is a trailing slash for client.V2 basePath
+ basePathV2 := strings.TrimSuffix(basePath, "/") + "/"
+ cfv2Options = append(cfv2Options, option.WithBaseURL(fmt.Sprintf("https://%s%s", baseHostname, basePathV2)))
if !data.RPS.IsNull() {
rps = int64(data.RPS.ValueInt64())
@@ -352,6 +364,7 @@ func (p *CloudflareProvider) Configure(ctx context.Context, req provider.Configu
func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
+ cloud_connector_rules.NewResource,
d1.NewResource,
email_routing_address.NewResource,
email_routing_rule.NewResource,
@@ -359,10 +372,14 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re
list_item.NewResource,
r2_bucket.NewResource,
risk_behavior.NewResource,
+ zero_trust_risk_behavior.NewResource,
rulesets.NewResource,
turnstile.NewResource,
access_mutual_tls_hostname_settings.NewResource,
- workers_for_platforms.NewResource,
+ zero_trust_access_mtls_hostname_settings.NewResource,
+ workers_for_platforms_dispatch_namespace_deprecated.NewResource,
+ workers_for_platforms_dispatch_namespace.NewResource,
+ zero_trust_risk_score_integration.NewResource,
}
}
@@ -372,6 +389,8 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc
origin_ca_certificate.NewDataSource,
user.NewDataSource,
dlp_datasets.NewDataSource,
+ gateway_categories.NewDataSource,
+ gateway_app_types.NewDataSource,
}
}
diff --git a/internal/framework/service/access_mutual_tls_hostname_settings/resource_test.go b/internal/framework/service/access_mutual_tls_hostname_settings/resource_test.go
index 6cd255dec1..c7cc2e811d 100644
--- a/internal/framework/service/access_mutual_tls_hostname_settings/resource_test.go
+++ b/internal/framework/service/access_mutual_tls_hostname_settings/resource_test.go
@@ -15,8 +15,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_access_mutual_tls_hostname_settings", &resource.Sweeper{
- Name: "cloudflare_access_mutual_tls_hostname_settings",
+ resource.AddTestSweepers("cloudflare_zero_trust_access_mtls_hostname_settings", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_mtls_hostname_settings",
F: func(region string) error {
ctx := context.Background()
@@ -55,7 +55,7 @@ func TestAccCloudflareAccessMutualTLSHostnameSettings_Simple(t *testing.T) {
}
rnd := utils.GenerateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_mutual_tls_hostname_settings.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_mtls_hostname_settings.%s", rnd)
domain := os.Getenv("CLOUDFLARE_DOMAIN")
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
@@ -87,7 +87,7 @@ func testAccCheckCloudflareAccessMutualTLSHostnameSettingsDestroy(s *terraform.S
}
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_mutual_tls_hostname_settings" {
+ if rs.Type != "cloudflare_zero_trust_access_mtls_hostname_settings" {
continue
}
@@ -111,7 +111,7 @@ func testAccCheckCloudflareAccessMutualTLSHostnameSettingsDestroy(s *terraform.S
func testAccessMutualTLSHostnameSettingsConfig(rnd string, identifier *cfv1.ResourceContainer, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_mutual_tls_hostname_settings" "%[1]s" {
+resource "cloudflare_zero_trust_access_mtls_hostname_settings" "%[1]s" {
%[2]s_id = "%[3]s"
settings {
hostname = "%[4]s"
diff --git a/internal/framework/service/access_mutual_tls_hostname_settings/schema.go b/internal/framework/service/access_mutual_tls_hostname_settings/schema.go
index 6882f665de..c9111af376 100644
--- a/internal/framework/service/access_mutual_tls_hostname_settings/schema.go
+++ b/internal/framework/service/access_mutual_tls_hostname_settings/schema.go
@@ -14,7 +14,8 @@ import (
func (r *AccessMutualTLSHostnameSettingsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Description: "Provides a Cloudflare Access Mutual TLS Certificate Settings resource.",
+ DeprecationMessage: "`cloudflare_access_mutual_tls_hostname_settings` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_mtls_hostname_settings` instead.",
+ Description: "Provides a Cloudflare Access Mutual TLS Certificate Settings resource.",
Attributes: map[string]schema.Attribute{
consts.AccountIDSchemaKey: schema.StringAttribute{
Description: consts.AccountIDSchemaDescription,
diff --git a/internal/framework/service/cloud_connector_rules/model.go b/internal/framework/service/cloud_connector_rules/model.go
new file mode 100644
index 0000000000..3313f34424
--- /dev/null
+++ b/internal/framework/service/cloud_connector_rules/model.go
@@ -0,0 +1,20 @@
+package cloud_connector_rules
+
+import "github.com/hashicorp/terraform-plugin-framework/types"
+
+type CloudConnectorRules struct {
+ ZoneID types.String `tfsdk:"zone_id"`
+ Rules []CloudConnectorRule `tfsdk:"rules"`
+}
+
+type CloudConnectorRule struct {
+ Enabled types.Bool `tfsdk:"enabled"`
+ Expression types.String `tfsdk:"expression"`
+ Provider types.String `tfsdk:"provider"`
+ Description types.String `tfsdk:"description"`
+ Parameters CloudConnectorRuleParameters `tfsdk:"parameters"`
+}
+
+type CloudConnectorRuleParameters struct {
+ Host types.String `tfsdk:"host"`
+}
diff --git a/internal/framework/service/cloud_connector_rules/resource.go b/internal/framework/service/cloud_connector_rules/resource.go
new file mode 100644
index 0000000000..4af521e857
--- /dev/null
+++ b/internal/framework/service/cloud_connector_rules/resource.go
@@ -0,0 +1,170 @@
+package cloud_connector_rules
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ cfv1 "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces.
+var _ resource.Resource = &CloudConnectorRulesResource{}
+var _ resource.ResourceWithImportState = &CloudConnectorRulesResource{}
+
+// CloudConnectorRulesResource defines the resource implementation.
+type CloudConnectorRulesResource struct {
+ client *muxclient.Client
+}
+
+func NewResource() resource.Resource {
+ return &CloudConnectorRulesResource{}
+}
+
+func (r *CloudConnectorRulesResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cloud_connector_rules"
+}
+
+func (r *CloudConnectorRulesResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*muxclient.Client)
+
+ if !ok {
+ resp.Diagnostics.AddError(
+ "unexpected resource configure type",
+ fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+
+ return
+ }
+
+ r.client = client
+}
+
+func resourceFromAPIResponse(data *CloudConnectorRules, rules []cfv1.CloudConnectorRule) {
+ result := make([]CloudConnectorRule, len(rules))
+ for i, rule := range rules {
+ result[i].Description = types.StringValue(rule.Description)
+ result[i].Expression = types.StringValue(rule.Expression)
+ result[i].Provider = types.StringValue(rule.Provider)
+ result[i].Enabled = types.BoolPointerValue(rule.Enabled)
+ result[i].Parameters.Host = types.StringValue(rule.Parameters.Host)
+ }
+ data.Rules = result
+}
+
+func requestFromResource(data *CloudConnectorRules) []cfv1.CloudConnectorRule {
+ rules := make([]cfv1.CloudConnectorRule, len(data.Rules))
+ for i, rule := range data.Rules {
+ rules[i] = cfv1.CloudConnectorRule{
+ Enabled: rule.Enabled.ValueBoolPointer(),
+ Expression: rule.Expression.ValueString(),
+ Provider: rule.Provider.ValueString(),
+ Parameters: cfv1.CloudConnectorRuleParameters{
+ Host: rule.Parameters.Host.ValueString(),
+ },
+ Description: rule.Description.ValueString(),
+ }
+ }
+ return rules
+}
+
+func (r *CloudConnectorRulesResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *CloudConnectorRules
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ rules, err := r.client.V1.UpdateZoneCloudConnectorRules(ctx, cfv1.ZoneIdentifier(data.ZoneID.ValueString()),
+ requestFromResource(data),
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed to create cloud connector rules", err.Error())
+ return
+ }
+
+ resourceFromAPIResponse(data, rules)
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *CloudConnectorRulesResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *CloudConnectorRules
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ rules, err := r.client.V1.ListZoneCloudConnectorRules(ctx, cfv1.ZoneIdentifier(data.ZoneID.ValueString()))
+ if err != nil {
+ resp.Diagnostics.AddError("failed reading cloud connector rules", err.Error())
+ return
+ }
+ resourceFromAPIResponse(data, rules)
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *CloudConnectorRulesResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data *CloudConnectorRules
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ rules, err := r.client.V1.UpdateZoneCloudConnectorRules(ctx, cfv1.ZoneIdentifier(data.ZoneID.ValueString()),
+ requestFromResource(data),
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed to create cloud connector rules", err.Error())
+ return
+ }
+
+ resourceFromAPIResponse(data, rules)
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *CloudConnectorRulesResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data *CloudConnectorRules
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ _, err := r.client.V1.UpdateZoneCloudConnectorRules(ctx, cfv1.ZoneIdentifier(data.ZoneID.ValueString()), []cfv1.CloudConnectorRule{})
+
+ if err != nil {
+ resp.Diagnostics.AddError("failed to delete cloud connector rules", err.Error())
+ return
+ }
+}
+
+func (r *CloudConnectorRulesResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ idparts := strings.Split(req.ID, "/")
+ if len(idparts) != 2 {
+ resp.Diagnostics.AddError("error importing cloud connector rule", `invalid ID specified. Please specify the ID as "/"`)
+ return
+ }
+ resp.Diagnostics.Append(resp.State.SetAttribute(
+ ctx, path.Root("zone_id"), idparts[0],
+ )...)
+ resp.Diagnostics.Append(resp.State.SetAttribute(
+ ctx, path.Root("id"), idparts[1],
+ )...)
+}
diff --git a/internal/framework/service/cloud_connector_rules/resource_test.go b/internal/framework/service/cloud_connector_rules/resource_test.go
new file mode 100644
index 0000000000..723db7edac
--- /dev/null
+++ b/internal/framework/service/cloud_connector_rules/resource_test.go
@@ -0,0 +1,171 @@
+package cloud_connector_rules_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ cloudflare "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/pkg/errors"
+)
+
+func TestMain(m *testing.M) {
+ resource.TestMain(m)
+}
+
+func init() {
+ resource.AddTestSweepers("cloudflare_cloud_connector_rules", &resource.Sweeper{
+ Name: "cloudflare_cloud_connector_rules",
+ F: testSweepCloudflareCloudConnectorRules,
+ })
+}
+
+func testSweepCloudflareCloudConnectorRules(r string) error {
+ ctx := context.Background()
+ client, clientErr := acctest.SharedV1Client()
+ 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")
+ }
+
+ _, err := client.UpdateZoneCloudConnectorRules(context.Background(), cloudflare.ZoneIdentifier(zone), []cloudflare.CloudConnectorRule{})
+ if err != nil {
+ tflog.Error(ctx, fmt.Sprintf("Failed to disable Cloudflare Zone Cloud Connector Rules: %s", err))
+ }
+
+ return nil
+}
+
+func TestAccCloudflareCloudConnectorRules(t *testing.T) {
+ t.Parallel()
+
+ rnd := utils.GenerateRandomResourceName()
+ zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
+ resourceName := "cloudflare_cloud_connector_rules." + rnd
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareCloudConnectorRules(rnd, zoneID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, consts.ZoneIDSchemaKey, zoneID),
+ resource.TestCheckResourceAttr(resourceName, "rules.#", "3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.%", "5"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.expression", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.description", "some description 1"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.provider", "aws_s3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.parameters.host", "mystorage1.s3.ams.amazonaws.com"),
+
+ resource.TestCheckResourceAttr(resourceName, "rules.1.%", "5"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.expression", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.description", "some description 2"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.provider", "aws_s3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.parameters.host", "mystorage2.s3.ams.amazonaws.com"),
+
+ resource.TestCheckResourceAttr(resourceName, "rules.2.%", "5"),
+ resource.TestCheckResourceAttr(resourceName, "rules.2.enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.2.expression", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.2.description", "some description 3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.2.provider", "aws_s3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.2.parameters.host", "mystorage3.s3.ams.amazonaws.com"),
+ ),
+ },
+ {
+ Config: testAccCheckCloudflareCloudConnectorRulesRemovedRule(rnd, zoneID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, consts.ZoneIDSchemaKey, zoneID),
+ resource.TestCheckResourceAttr(resourceName, "rules.#", "2"),
+
+ resource.TestCheckResourceAttr(resourceName, "rules.0.%", "5"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.expression", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.description", "some description 2"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.provider", "aws_s3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.0.parameters.host", "mystorage2.s3.ams.amazonaws.com"),
+
+ resource.TestCheckResourceAttr(resourceName, "rules.1.%", "5"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.expression", "true"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.description", "some description 3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.provider", "aws_s3"),
+ resource.TestCheckResourceAttr(resourceName, "rules.1.parameters.host", "mystorage3.s3.ams.amazonaws.com"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareCloudConnectorRules(rnd, zoneID string) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_cloud_connector_rules" "%[1]s" {
+ zone_id = "%[2]s"
+ rules {
+ enabled = true
+ expression = "true"
+ provider = "aws_s3"
+ description = "some description 1"
+ parameters {
+ host = "mystorage1.s3.ams.amazonaws.com"
+ }
+ }
+
+ rules {
+ enabled = true
+ expression = "true"
+ provider = "aws_s3"
+ description = "some description 2"
+ parameters {
+ host = "mystorage2.s3.ams.amazonaws.com"
+ }
+ }
+
+ rules {
+ enabled = true
+ expression = "true"
+ provider = "aws_s3"
+ description = "some description 3"
+ parameters {
+ host = "mystorage3.s3.ams.amazonaws.com"
+ }
+ }
+ }`, rnd, zoneID)
+}
+
+func testAccCheckCloudflareCloudConnectorRulesRemovedRule(rnd, zoneID string) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_cloud_connector_rules" "%[1]s" {
+ zone_id = "%[2]s"
+ rules {
+ enabled = true
+ expression = "true"
+ provider = "aws_s3"
+ description = "some description 2"
+ parameters {
+ host = "mystorage2.s3.ams.amazonaws.com"
+ }
+ }
+
+ rules {
+ enabled = true
+ expression = "true"
+ provider = "aws_s3"
+ description = "some description 3"
+ parameters {
+ host = "mystorage3.s3.ams.amazonaws.com"
+ }
+ }
+ }`, rnd, zoneID)
+}
diff --git a/internal/framework/service/cloud_connector_rules/schema.go b/internal/framework/service/cloud_connector_rules/schema.go
new file mode 100644
index 0000000000..f5f27a3aee
--- /dev/null
+++ b/internal/framework/service/cloud_connector_rules/schema.go
@@ -0,0 +1,89 @@
+package cloud_connector_rules
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/MakeNowJust/heredoc/v2"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+)
+
+func (r *CloudConnectorRulesResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: heredoc.Doc(`
+ The [Cloud Connector Rules](add link to doc) resource allows you to create and manage cloud connector rules for a zone.
+ `),
+ Version: 1,
+
+ Attributes: map[string]schema.Attribute{
+ consts.ZoneIDSchemaKey: schema.StringAttribute{
+ MarkdownDescription: consts.ZoneIDSchemaDescription,
+ Required: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ },
+ Blocks: map[string]schema.Block{
+ "rules": schema.SetNestedBlock{
+ MarkdownDescription: "List of Cloud Connector Rules",
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
+ setvalidator.IsRequired(),
+ },
+ NestedObject: schema.NestedBlockObject{
+ Attributes: map[string]schema.Attribute{
+ "provider": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: fmt.Sprintf("Type of provider. %s", utils.RenderAvailableDocumentationValuesStringSlice([]string{
+ "aws_s3",
+ "cloudflare_r2",
+ "azure_storage",
+ "gcp_storage",
+ })),
+ Validators: []validator.String{
+ stringvalidator.OneOf(
+ "aws_s3",
+ "cloudflare_r2",
+ "azure_storage",
+ "gcp_storage",
+ ),
+ },
+ },
+ "enabled": schema.BoolAttribute{
+ Optional: true,
+ MarkdownDescription: "Whether the headers rule is active.",
+ },
+ "expression": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Criteria for an HTTP request to trigger the cloud connector rule. Uses the Firewall Rules expression language based on Wireshark display filters.",
+ },
+ "description": schema.StringAttribute{
+ Optional: true,
+ MarkdownDescription: "Brief summary of the cloud connector rule and its intended use.",
+ },
+ },
+ Blocks: map[string]schema.Block{
+ "parameters": schema.SingleNestedBlock{
+ MarkdownDescription: "Cloud Connector Rule Parameters",
+ Attributes: map[string]schema.Attribute{
+ "host": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Host parameter for cloud connector rule",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/internal/framework/service/gateway_app_types/data_source.go b/internal/framework/service/gateway_app_types/data_source.go
new file mode 100644
index 0000000000..7211fd9d88
--- /dev/null
+++ b/internal/framework/service/gateway_app_types/data_source.go
@@ -0,0 +1,74 @@
+package gateway_app_types
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/cloudflare/cloudflare-go/v2"
+ "github.com/cloudflare/cloudflare-go/v2/zero_trust"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var _ datasource.DataSource = &CloudflareGatewayAppTypesDataSource{}
+
+func NewDataSource() datasource.DataSource {
+ return &CloudflareGatewayAppTypesDataSource{}
+}
+
+type CloudflareGatewayAppTypesDataSource struct {
+ client *muxclient.Client
+}
+
+func (d *CloudflareGatewayAppTypesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_gateway_app_types"
+}
+
+func (d *CloudflareGatewayAppTypesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*muxclient.Client)
+ if !ok {
+ resp.Diagnostics.AddError(
+ "Unexpected resource configure type",
+ fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+ return
+ }
+
+ d.client = client
+}
+
+func (d *CloudflareGatewayAppTypesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var data GatewayAppTypesModel
+
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+ params := zero_trust.GatewayAppTypeListParams{
+ AccountID: cloudflare.F(data.AccountID.ValueString()),
+ }
+
+ iter := d.client.V2.ZeroTrust.Gateway.AppTypes.ListAutoPaging(ctx, params)
+ var appTypes []GatewayAppTypeModel
+
+ for iter.Next() {
+ appType := iter.Current()
+
+ appTypes = append(appTypes, GatewayAppTypeModel{
+ ID: types.Int64Value(appType.ID),
+ ApplicationTypeID: types.Int64Value(appType.ApplicationTypeID),
+ Name: types.StringValue(appType.Name),
+ Description: types.StringValue(appType.Description),
+ })
+ }
+ if err := iter.Err(); err != nil {
+ resp.Diagnostics.AddError("Failed to fetch Gateway App Types", err.Error())
+ return
+ }
+
+ data.AppTypes = appTypes
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/internal/framework/service/gateway_app_types/data_source_test.go b/internal/framework/service/gateway_app_types/data_source_test.go
new file mode 100644
index 0000000000..132419ec37
--- /dev/null
+++ b/internal/framework/service/gateway_app_types/data_source_test.go
@@ -0,0 +1,36 @@
+package gateway_app_types_test
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccCloudflareGatewayAppTypes_DataSource(t *testing.T) {
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareGatewayAppTypesDataSourceConfig(accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrSet("data.cloudflare_gateway_app_types.my_app_types", "account_id"),
+ resource.TestCheckResourceAttrSet("data.cloudflare_gateway_app_types.my_app_types", "app_types.#"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareGatewayAppTypesDataSourceConfig(accountID string) string {
+ return fmt.Sprintf(`
+data "cloudflare_gateway_app_types" "my_app_types" {
+ account_id = "%s"
+}
+`, accountID)
+}
diff --git a/internal/framework/service/gateway_app_types/model.go b/internal/framework/service/gateway_app_types/model.go
new file mode 100644
index 0000000000..411c5a3118
--- /dev/null
+++ b/internal/framework/service/gateway_app_types/model.go
@@ -0,0 +1,17 @@
+package gateway_app_types
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type GatewayAppTypesModel struct {
+ AccountID types.String `tfsdk:"account_id"`
+ AppTypes []GatewayAppTypeModel `tfsdk:"app_types"`
+}
+
+type GatewayAppTypeModel struct {
+ ID types.Int64 `tfsdk:"id"`
+ ApplicationTypeID types.Int64 `tfsdk:"application_type_id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+}
diff --git a/internal/framework/service/gateway_app_types/schema.go b/internal/framework/service/gateway_app_types/schema.go
new file mode 100644
index 0000000000..079ef36f9e
--- /dev/null
+++ b/internal/framework/service/gateway_app_types/schema.go
@@ -0,0 +1,44 @@
+package gateway_app_types
+
+import (
+ "context"
+
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+)
+
+func (d *CloudflareGatewayAppTypesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Description: "Use this data source to retrieve all Gateway application types for an account.",
+ Attributes: map[string]schema.Attribute{
+ "account_id": schema.StringAttribute{
+ Required: true,
+ Description: "The account ID to fetch Gateway App Types from.",
+ },
+ "app_types": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "A list of Gateway App Types.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.Int64Attribute{
+ Computed: true,
+ Description: "The identifier for this app type. There is only one app type per ID.",
+ },
+ "application_type_id": schema.Int64Attribute{
+ Computed: true,
+ Description: "The identifier for the application type of this app.",
+ },
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "The name of the app type.",
+ },
+ "description": schema.StringAttribute{
+ Computed: true,
+ Description: "A short summary of the app type.",
+ },
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/internal/framework/service/gateway_categories/data_source.go b/internal/framework/service/gateway_categories/data_source.go
new file mode 100644
index 0000000000..ca62bc5376
--- /dev/null
+++ b/internal/framework/service/gateway_categories/data_source.go
@@ -0,0 +1,92 @@
+package gateway_categories
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/cloudflare/cloudflare-go/v2"
+ "github.com/cloudflare/cloudflare-go/v2/zero_trust"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var _ datasource.DataSource = &CloudflareGatewayCategoriesDataSource{}
+
+func NewDataSource() datasource.DataSource {
+ return &CloudflareGatewayCategoriesDataSource{}
+}
+
+type CloudflareGatewayCategoriesDataSource struct {
+ client *muxclient.Client
+}
+
+func (d *CloudflareGatewayCategoriesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_gateway_categories"
+}
+
+func (d *CloudflareGatewayCategoriesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*muxclient.Client)
+ if !ok {
+ resp.Diagnostics.AddError(
+ "Unexpected resource configure type",
+ fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+ return
+ }
+
+ d.client = client
+}
+
+func (d *CloudflareGatewayCategoriesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var data GatewayCategoriesModel
+
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+ params := zero_trust.GatewayCategoryListParams{
+ AccountID: cloudflare.F(data.AccountID.ValueString()),
+ }
+
+ // Create a new Gateway Category Service
+ service := zero_trust.NewGatewayCategoryService(d.client.V2.Options...)
+
+ // Retrieve categories - v2 SDK way
+ iter := service.ListAutoPaging(ctx, params)
+ var categories []GatewayCategoryModel
+
+ for iter.Next() {
+ category := iter.Current()
+
+ // Map subcategories
+ var subcategories []GatewaySubCategoryModel
+ for _, subcategory := range category.Subcategories {
+ subcategories = append(subcategories, GatewaySubCategoryModel{
+ ID: types.Int64Value(subcategory.ID),
+ Name: types.StringValue(subcategory.Name),
+ Description: types.StringValue(subcategory.Description),
+ Class: types.StringValue(string(subcategory.Class)),
+ Beta: types.BoolValue(subcategory.Beta),
+ })
+ }
+
+ categories = append(categories, GatewayCategoryModel{
+ ID: types.Int64Value(category.ID),
+ Name: types.StringValue(category.Name),
+ Description: types.StringValue(category.Description),
+ Class: types.StringValue(string(category.Class)),
+ Beta: types.BoolValue(category.Beta),
+ Subcategories: subcategories,
+ })
+ }
+ if err := iter.Err(); err != nil {
+ resp.Diagnostics.AddError("Failed to fetch Gateway Categories", err.Error())
+ return
+ }
+
+ data.Categories = categories
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/internal/framework/service/gateway_categories/data_source_test.go b/internal/framework/service/gateway_categories/data_source_test.go
new file mode 100644
index 0000000000..e8cf0919b2
--- /dev/null
+++ b/internal/framework/service/gateway_categories/data_source_test.go
@@ -0,0 +1,40 @@
+package gateway_categories_test
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccCloudflareGatewayCategories_DataSource(t *testing.T) {
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ if accountID == "" {
+ t.Fatal("CLOUDFLARE_ACCOUNT_ID must be set for acceptance tests")
+ }
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareGatewayCategoriesDataSourceConfig(accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrSet("data.cloudflare_gateway_categories.my_categories", "account_id"),
+ resource.TestCheckResourceAttrSet("data.cloudflare_gateway_categories.my_categories", "categories.#"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareGatewayCategoriesDataSourceConfig(accountID string) string {
+ return fmt.Sprintf(`
+data "cloudflare_gateway_categories" "my_categories" {
+ account_id = "%s"
+}
+`, accountID)
+}
diff --git a/internal/framework/service/gateway_categories/model.go b/internal/framework/service/gateway_categories/model.go
new file mode 100644
index 0000000000..3982e88c0d
--- /dev/null
+++ b/internal/framework/service/gateway_categories/model.go
@@ -0,0 +1,27 @@
+package gateway_categories
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type GatewayCategoriesModel struct {
+ AccountID types.String `tfsdk:"account_id"`
+ Categories []GatewayCategoryModel `tfsdk:"categories"`
+}
+
+type GatewayCategoryModel struct {
+ ID types.Int64 `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Class types.String `tfsdk:"class"`
+ Beta types.Bool `tfsdk:"beta"`
+ Subcategories []GatewaySubCategoryModel `tfsdk:"subcategories"`
+}
+
+type GatewaySubCategoryModel struct {
+ ID types.Int64 `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Class types.String `tfsdk:"class"`
+ Beta types.Bool `tfsdk:"beta"`
+}
diff --git a/internal/framework/service/gateway_categories/schema.go b/internal/framework/service/gateway_categories/schema.go
new file mode 100644
index 0000000000..6874b288f1
--- /dev/null
+++ b/internal/framework/service/gateway_categories/schema.go
@@ -0,0 +1,76 @@
+package gateway_categories
+
+import (
+ "context"
+
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+)
+
+func (d *CloudflareGatewayCategoriesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Description: "Use this data source to retrieve all Gateway categories for an account.",
+ Attributes: map[string]schema.Attribute{
+ "account_id": schema.StringAttribute{
+ Required: true,
+ Description: "The account ID to fetch Gateway Categories from.",
+ },
+ "categories": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "A list of Gateway Categories.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.Int64Attribute{
+ Computed: true,
+ Description: "The identifier for this category. There is only one category per ID.",
+ },
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "The name of the category.",
+ },
+ "description": schema.StringAttribute{
+ Computed: true,
+ Description: "A short summary of domains in the category.",
+ },
+ "class": schema.StringAttribute{
+ Computed: true,
+ Description: "Which account types are allowed to create policies based on this category.",
+ },
+ "beta": schema.BoolAttribute{
+ Computed: true,
+ Description: "True if the category is in beta and subject to change.",
+ },
+ "subcategories": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "A list of subcategories.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.Int64Attribute{
+ Computed: true,
+ Description: "The identifier for this subcategory. There is only one subcategory per ID.",
+ },
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "The name of the subcategory.",
+ },
+ "description": schema.StringAttribute{
+ Computed: true,
+ Description: "A short summary of domains in the subcategory.",
+ },
+ "class": schema.StringAttribute{
+ Computed: true,
+ Description: "Which account types are allowed to create policies based on this subcategory.",
+ },
+ "beta": schema.BoolAttribute{
+ Computed: true,
+ Description: "True if the subcategory is in beta and subject to change.",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/internal/framework/service/hyperdrive_config/model.go b/internal/framework/service/hyperdrive_config/model.go
index 16977b0b7d..c96e9703f0 100644
--- a/internal/framework/service/hyperdrive_config/model.go
+++ b/internal/framework/service/hyperdrive_config/model.go
@@ -14,20 +14,26 @@ type HyperdriveConfigModel struct {
}
type HyperdriveConfigOriginModel struct {
- Database types.String `tfsdk:"database"`
- Password types.String `tfsdk:"password"`
- Host types.String `tfsdk:"host"`
- Port types.Int64 `tfsdk:"port"`
- Scheme types.String `tfsdk:"scheme"`
- User types.String `tfsdk:"user"`
+ Database types.String `tfsdk:"database"`
+ Password types.String `tfsdk:"password"`
+ Host types.String `tfsdk:"host"`
+ Port types.Int64 `tfsdk:"port"`
+ Scheme types.String `tfsdk:"scheme"`
+ User types.String `tfsdk:"user"`
+ AccessClientID types.String `tfsdk:"access_client_id"`
+ AccessClientSecret types.String `tfsdk:"access_client_secret"`
}
type HyperdriveConfigCachingModel struct {
- Disabled types.Bool `tfsdk:"disabled"`
+ Disabled types.Bool `tfsdk:"disabled"`
+ MaxAge types.Int64 `tfsdk:"max_age"`
+ StaleWhileRevalidate types.Int64 `tfsdk:"stale_while_revalidate"`
}
func (m HyperdriveConfigCachingModel) AttributeTypes() map[string]attr.Type {
return map[string]attr.Type{
- "disabled": types.BoolType,
+ "disabled": types.BoolType,
+ "max_age": types.Int64Type,
+ "stale_while_revalidate": types.Int64Type,
}
}
diff --git a/internal/framework/service/hyperdrive_config/resource.go b/internal/framework/service/hyperdrive_config/resource.go
index 65d964b719..9c89c89257 100644
--- a/internal/framework/service/hyperdrive_config/resource.go
+++ b/internal/framework/service/hyperdrive_config/resource.go
@@ -62,30 +62,16 @@ func (r *HyperdriveConfigResource) Create(ctx context.Context, req resource.Crea
return
}
- config := buildHyperdriveConfigFromModel(data, caching)
-
- createHyperdriveConfig, err := r.client.V1.CreateHyperdriveConfig(ctx, cfv1.AccountIdentifier(data.AccountID.ValueString()),
- cfv1.CreateHyperdriveConfigParams{
- Name: config.Name,
- Origin: cfv1.HyperdriveConfigOrigin{
- Database: config.Origin.Database,
- Password: config.Origin.Password,
- Host: config.Origin.Host,
- Port: config.Origin.Port,
- Scheme: config.Origin.Scheme,
- User: config.Origin.User,
- },
- Caching: cfv1.HyperdriveConfigCaching{
- Disabled: config.Caching.Disabled,
- },
- })
+ config := buildHyperdriveCreateUpdateConfigsFromModel(data, caching)
+
+ createHyperdriveConfig, err := r.client.V1.CreateHyperdriveConfig(ctx, cfv1.AccountIdentifier(data.AccountID.ValueString()), config)
if err != nil {
resp.Diagnostics.AddError("Error creating hyperdrive config", err.Error())
return
}
var diags diag.Diagnostics
- data, diags = buildHyperdriveConfigModelFromHyperdriveConfig(ctx, data, createHyperdriveConfig)
+ data, diags = buildHyperdriveConfigModelFromAPIResponse(ctx, data, createHyperdriveConfig)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -108,7 +94,7 @@ func (r *HyperdriveConfigResource) Read(ctx context.Context, req resource.ReadRe
}
var diags diag.Diagnostics
- data, diags = buildHyperdriveConfigModelFromHyperdriveConfig(ctx, data, config)
+ data, diags = buildHyperdriveConfigModelFromAPIResponse(ctx, data, config)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -125,22 +111,13 @@ func (r *HyperdriveConfigResource) Update(ctx context.Context, req resource.Upda
return
}
- config := buildHyperdriveConfigFromModel(data, caching)
+ config := buildHyperdriveCreateUpdateConfigsFromModel(data, caching)
updatedConfig, err := r.client.V1.UpdateHyperdriveConfig(ctx, cfv1.AccountIdentifier(data.AccountID.ValueString()), cfv1.UpdateHyperdriveConfigParams{
+ HyperdriveID: data.ID.String(),
Name: config.Name,
- HyperdriveID: config.ID,
- Origin: cfv1.HyperdriveConfigOrigin{
- Database: config.Origin.Database,
- Password: config.Origin.Password,
- Host: config.Origin.Host,
- Port: config.Origin.Port,
- Scheme: config.Origin.Scheme,
- User: config.Origin.User,
- },
- Caching: cfv1.HyperdriveConfigCaching{
- Disabled: config.Caching.Disabled,
- },
+ Origin: config.Origin,
+ Caching: config.Caching,
})
if err != nil {
@@ -149,7 +126,7 @@ func (r *HyperdriveConfigResource) Update(ctx context.Context, req resource.Upda
}
var diags diag.Diagnostics
- data, diags = buildHyperdriveConfigModelFromHyperdriveConfig(ctx, data, updatedConfig)
+ data, diags = buildHyperdriveConfigModelFromAPIResponse(ctx, data, updatedConfig)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -179,18 +156,27 @@ func (r *HyperdriveConfigResource) ImportState(ctx context.Context, req resource
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...)
}
-func buildHyperdriveConfigFromModel(config *HyperdriveConfigModel, caching *HyperdriveConfigCachingModel) cfv1.HyperdriveConfig {
- built := cfv1.HyperdriveConfig{
- ID: config.ID.ValueString(),
+func buildHyperdriveCreateUpdateConfigsFromModel(config *HyperdriveConfigModel, caching *HyperdriveConfigCachingModel) cfv1.CreateHyperdriveConfigParams {
+ built := cfv1.CreateHyperdriveConfigParams{
Name: config.Name.ValueString(),
- Origin: cfv1.HyperdriveConfigOrigin{
- Database: config.Origin.Database.ValueString(),
+ Origin: cfv1.HyperdriveConfigOriginWithSecrets{
+ HyperdriveConfigOrigin: cfv1.HyperdriveConfigOrigin{
+ Database: config.Origin.Database.ValueString(),
+ Host: config.Origin.Host.ValueString(),
+ },
Password: config.Origin.Password.ValueString(),
- Host: config.Origin.Host.ValueString(),
- Port: int(config.Origin.Port.ValueInt64()),
},
}
+ if !config.Origin.Port.IsNull() {
+ built.Origin.Port = int(config.Origin.Port.ValueInt64())
+ }
+
+ if !config.Origin.AccessClientID.IsNull() && !config.Origin.AccessClientSecret.IsNull() {
+ built.Origin.AccessClientID = config.Origin.AccessClientID.ValueString()
+ built.Origin.AccessClientSecret = config.Origin.AccessClientSecret.ValueString()
+ }
+
if !config.Origin.Scheme.IsNull() {
built.Origin.Scheme = config.Origin.Scheme.ValueString()
}
@@ -201,45 +187,61 @@ func buildHyperdriveConfigFromModel(config *HyperdriveConfigModel, caching *Hype
built.Caching = cfv1.HyperdriveConfigCaching{}
- if caching != nil && !caching.Disabled.IsNull() {
- built.Caching.Disabled = cfv1.BoolPtr(caching.Disabled.ValueBool())
+ if caching != nil {
+ if !caching.Disabled.IsNull() {
+ built.Caching.Disabled = cfv1.BoolPtr(caching.Disabled.ValueBool())
+ }
+ if !caching.MaxAge.IsNull() {
+ built.Caching.MaxAge = int(caching.MaxAge.ValueInt64())
+ }
+ if !caching.StaleWhileRevalidate.IsNull() {
+ built.Caching.StaleWhileRevalidate = int(caching.StaleWhileRevalidate.ValueInt64())
+ }
}
return built
}
-func buildHyperdriveConfigModelFromHyperdriveConfig(ctx context.Context, data *HyperdriveConfigModel, config cfv1.HyperdriveConfig) (*HyperdriveConfigModel, diag.Diagnostics) {
+func buildHyperdriveConfigModelFromAPIResponse(ctx context.Context, data *HyperdriveConfigModel, config cfv1.HyperdriveConfig) (*HyperdriveConfigModel, diag.Diagnostics) {
var scheme = flatteners.String("postgres")
if data.Origin != nil {
scheme = data.Origin.Scheme
}
var password = flatteners.String("")
+ var accessClientSecret = flatteners.String("")
if data.Origin != nil {
password = data.Origin.Password
+ accessClientSecret = data.Origin.AccessClientSecret
}
var caching, diags = types.ObjectValueFrom(
ctx,
HyperdriveConfigCachingModel{}.AttributeTypes(),
HyperdriveConfigCachingModel{
- Disabled: types.BoolValue(*config.Caching.Disabled),
+ Disabled: types.BoolValue(*config.Caching.Disabled),
+ MaxAge: flatteners.Int64(int64(config.Caching.MaxAge)),
+ StaleWhileRevalidate: flatteners.Int64(int64(config.Caching.StaleWhileRevalidate)),
},
)
+ origin := HyperdriveConfigOriginModel{
+ Database: flatteners.String(config.Origin.Database),
+ Host: flatteners.String(config.Origin.Host),
+ Port: flatteners.Int64(int64(config.Origin.Port)),
+ User: flatteners.String(config.Origin.User),
+ Scheme: scheme,
+ Password: password,
+ AccessClientID: flatteners.String(config.Origin.AccessClientID),
+ AccessClientSecret: accessClientSecret,
+ }
+
built := HyperdriveConfigModel{
AccountID: data.AccountID,
ID: flatteners.String(config.ID),
Name: flatteners.String(config.Name),
- Origin: &HyperdriveConfigOriginModel{
- Database: flatteners.String(config.Origin.Database),
- Host: flatteners.String(config.Origin.Host),
- Port: flatteners.Int64(int64(config.Origin.Port)),
- User: flatteners.String(config.Origin.User),
- Scheme: scheme,
- Password: password,
- },
- Caching: caching,
+ Origin: &origin,
+ Caching: caching,
}
return &built, diags
diff --git a/internal/framework/service/hyperdrive_config/resource_test.go b/internal/framework/service/hyperdrive_config/resource_test.go
index 2fc81dbbcf..094a79ed46 100644
--- a/internal/framework/service/hyperdrive_config/resource_test.go
+++ b/internal/framework/service/hyperdrive_config/resource_test.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
+ "strconv"
"testing"
cfv1 "github.com/cloudflare/cloudflare-go"
@@ -11,6 +12,7 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
)
func TestMain(m *testing.M) {
@@ -52,14 +54,21 @@ func TestAccCloudflareHyperdriveConfig_Basic(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+ databaseName := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME")
+ databaseHostname := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME")
+ databasePort := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PORT")
+ port, _ := strconv.Atoi(databasePort)
+ databaseUser := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_USER")
+ databasePassword := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD")
+
resourceName := "cloudflare_hyperdrive_config." + rnd
var origin = cfv1.HyperdriveConfigOrigin{
- Database: "database",
- Host: "host.example.com",
- Port: 5432,
+ Database: databaseName,
+ Host: databaseHostname,
+ Port: port,
Scheme: "postgres",
- User: "user",
+ User: databaseUser,
}
var disabled = true
@@ -68,29 +77,49 @@ func TestAccCloudflareHyperdriveConfig_Basic(t *testing.T) {
Disabled: &disabled,
}
+ var configID string
+ updatedName := rnd + "-updated"
+
resource.ParallelTest(t, resource.TestCase{
- PreCheck: func() { acctest.TestAccPreCheck(t) },
+ PreCheck: func() {
+ acctest.TestAccPreCheck(t)
+ acctest.TestAccPreCheck_Hyperdrive(t)
+ },
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
- Config: testHyperdriveConfigConfig(
+ Config: testHyperdriveConfig(
rnd,
accountID,
rnd,
- "password",
+ databasePassword,
origin,
caching,
),
Check: resource.ComposeTestCheckFunc(
+ // use a test check function to grab the id that was generated by the API
+ func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ configID = rs.Primary.Attributes["id"]
+ return nil
+ },
resource.TestCheckResourceAttr(resourceName, "name", rnd),
resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
- resource.TestCheckResourceAttr(resourceName, "origin.database", "database"),
- resource.TestCheckResourceAttr(resourceName, "origin.host", "host.example.com"),
- resource.TestCheckResourceAttr(resourceName, "origin.port", "5432"),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckResourceAttr(resourceName, "origin.port", databasePort),
resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
- resource.TestCheckResourceAttr(resourceName, "origin.user", "user"),
- resource.TestCheckResourceAttr(resourceName, "origin.password", "password"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.access_client_id"),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.access_client_secret"),
resource.TestCheckResourceAttr(resourceName, "caching.disabled", "true"),
+ resource.TestCheckNoResourceAttr(resourceName, "caching.max_age"),
+ resource.TestCheckNoResourceAttr(resourceName, "caching.stale_while_revalidate"),
),
},
{
@@ -100,6 +129,208 @@ func TestAccCloudflareHyperdriveConfig_Basic(t *testing.T) {
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"origin.password"},
},
+ {
+ Config: testHyperdriveConfigUpdate(
+ rnd,
+ configID,
+ accountID,
+ updatedName,
+ databasePassword,
+ origin,
+ caching,
+ ),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "name", updatedName),
+ resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckResourceAttr(resourceName, "origin.port", databasePort),
+ resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
+ resource.TestCheckResourceAttr(resourceName, "caching.disabled", "false"),
+ ),
+ },
+ },
+ })
+}
+
+func TestAccCloudflareHyperdriveConfig_CachingSettings(t *testing.T) {
+ acctest.TestAccSkipForDefaultAccount(t, "Requires real Postgres instance to be available.")
+
+ rnd := utils.GenerateRandomResourceName()
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+ databaseName := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME")
+ databaseHostname := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME")
+ databasePort := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PORT")
+ port, _ := strconv.Atoi(databasePort)
+ databaseUser := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_USER")
+ databasePassword := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD")
+ resourceName := "cloudflare_hyperdrive_config." + rnd
+
+ var origin = cfv1.HyperdriveConfigOrigin{
+ Database: databaseName,
+ Host: databaseHostname,
+ Port: port,
+ Scheme: "postgres",
+ User: databaseUser,
+ }
+
+ var disabled = false
+
+ var caching = cfv1.HyperdriveConfigCaching{
+ Disabled: &disabled,
+ MaxAge: 60,
+ StaleWhileRevalidate: 30,
+ }
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() {
+ acctest.TestAccPreCheck(t)
+ acctest.TestAccPreCheck_Hyperdrive(t)
+ },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testHyperdriveConfigFullCachingSettings(
+ rnd,
+ accountID,
+ rnd,
+ databasePassword,
+ origin,
+ caching,
+ ),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "name", rnd),
+ resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckResourceAttr(resourceName, "origin.port", databasePort),
+ resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.access_client_id"),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.access_client_secret"),
+ resource.TestCheckResourceAttr(resourceName, "caching.disabled", "false"),
+ resource.TestCheckResourceAttr(resourceName, "caching.max_age", "60"),
+ resource.TestCheckResourceAttr(resourceName, "caching.stale_while_revalidate", "30"),
+ ),
+ },
+ {
+ ResourceName: resourceName,
+ ImportStateIdPrefix: fmt.Sprintf("%s/", accountID),
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"origin.password"},
+ },
+ },
+ })
+}
+
+func TestAccCloudflareHyperdriveConfig_HyperdriveOverAccess(t *testing.T) {
+ acctest.TestAccSkipForDefaultAccount(t, "Requires real Postgres instance to be available.")
+
+ rnd := utils.GenerateRandomResourceName()
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+ databaseName := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME")
+ databaseHostname := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME")
+ databaseUser := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_USER")
+ databasePassword := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD")
+ accessClientID := os.Getenv("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_ID")
+ accessClientSecret := os.Getenv("CLOUDFLARE_HYPERDRIVE_ACCESS_CLIENT_SECRET")
+ resourceName := "cloudflare_hyperdrive_config." + rnd
+
+ var origin = cfv1.HyperdriveConfigOriginWithSecrets{
+ HyperdriveConfigOrigin: cfv1.HyperdriveConfigOrigin{
+ Database: databaseName,
+ Host: databaseHostname,
+ Scheme: "postgres",
+ User: databaseUser,
+ AccessClientID: accessClientID,
+ },
+ AccessClientSecret: accessClientSecret,
+ }
+
+ var disabled = true
+
+ var caching = cfv1.HyperdriveConfigCaching{
+ Disabled: &disabled,
+ }
+
+ var configID string
+ updatedName := rnd + "-updated"
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() {
+ acctest.TestAccPreCheck(t)
+ acctest.TestAccPreCheck_HyperdriveWithAccess(t)
+ },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testHyperdriveOverAccessConfig(
+ rnd,
+ accountID,
+ rnd,
+ databasePassword,
+ origin,
+ caching,
+ ),
+ Check: resource.ComposeTestCheckFunc(
+ // use a test check function to grab the id that was generated by the API
+ func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ configID = rs.Primary.Attributes["id"]
+ return nil
+ },
+ resource.TestCheckResourceAttr(resourceName, "name", rnd),
+ resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.port"),
+ resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
+ resource.TestCheckResourceAttr(resourceName, "origin.access_client_id", accessClientID),
+ resource.TestCheckResourceAttr(resourceName, "origin.access_client_secret", accessClientSecret),
+ resource.TestCheckResourceAttr(resourceName, "caching.disabled", "true"),
+ ),
+ },
+ {
+ ResourceName: resourceName,
+ ImportStateIdPrefix: fmt.Sprintf("%s/", accountID),
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"origin.password", "origin.access_client_secret"},
+ },
+ {
+ Config: testHyperdriveOverAccessUpdate(
+ rnd,
+ configID,
+ accountID,
+ updatedName,
+ databasePassword,
+ origin,
+ caching,
+ ),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "name", updatedName),
+ resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckNoResourceAttr(resourceName, "origin.port"),
+ resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
+ resource.TestCheckResourceAttr(resourceName, "origin.access_client_id", accessClientID),
+ resource.TestCheckResourceAttr(resourceName, "origin.access_client_secret", accessClientSecret),
+ resource.TestCheckResourceAttr(resourceName, "caching.disabled", "true"),
+ ),
+ },
},
})
}
@@ -109,18 +340,27 @@ func TestAccCloudflareHyperdriveConfig_Minimum(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+ databaseName := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_NAME")
+ databaseHostname := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME")
+ databasePort := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PORT")
+ port, _ := strconv.Atoi(databasePort)
+ databaseUser := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_USER")
+ databasePassword := os.Getenv("CLOUDFLARE_HYPERDRIVE_DATABASE_PASSWORD")
resourceName := "cloudflare_hyperdrive_config." + rnd
var origin = cfv1.HyperdriveConfigOrigin{
- Database: "database",
- Host: "host.example.com",
- Port: 5432,
+ Database: databaseName,
+ Host: databaseHostname,
+ Port: port,
Scheme: "postgres",
- User: "user",
+ User: databaseUser,
}
resource.ParallelTest(t, resource.TestCase{
- PreCheck: func() { acctest.TestAccPreCheck(t) },
+ PreCheck: func() {
+ acctest.TestAccPreCheck(t)
+ acctest.TestAccPreCheck_Hyperdrive(t)
+ },
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
@@ -128,18 +368,18 @@ func TestAccCloudflareHyperdriveConfig_Minimum(t *testing.T) {
rnd,
accountID,
rnd,
- "password",
+ databasePassword,
origin,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", rnd),
resource.TestCheckResourceAttr(resourceName, "account_id", accountID),
- resource.TestCheckResourceAttr(resourceName, "origin.database", "database"),
- resource.TestCheckResourceAttr(resourceName, "origin.host", "host.example.com"),
- resource.TestCheckResourceAttr(resourceName, "origin.port", "5432"),
+ resource.TestCheckResourceAttr(resourceName, "origin.database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "origin.host", databaseHostname),
+ resource.TestCheckResourceAttr(resourceName, "origin.port", databasePort),
resource.TestCheckResourceAttr(resourceName, "origin.scheme", "postgres"),
- resource.TestCheckResourceAttr(resourceName, "origin.user", "user"),
- resource.TestCheckResourceAttr(resourceName, "origin.password", "password"),
+ resource.TestCheckResourceAttr(resourceName, "origin.user", databaseUser),
+ resource.TestCheckResourceAttr(resourceName, "origin.password", databasePassword),
resource.TestCheckResourceAttr(resourceName, "caching.disabled", "false"),
),
},
@@ -154,7 +394,73 @@ func TestAccCloudflareHyperdriveConfig_Minimum(t *testing.T) {
})
}
-func testHyperdriveConfigConfig(
+func testHyperdriveConfig(
+ rnd, accountId, name string, password string, origin cfv1.HyperdriveConfigOrigin, caching cfv1.HyperdriveConfigCaching,
+) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_hyperdrive_config" "%[1]s" {
+ account_id = "%[2]s"
+ name = "%[3]s"
+ origin = {
+ password = "%[4]s"
+ database = "%[5]s"
+ host = "%[6]s"
+ port = "%[7]s"
+ scheme = "%[8]s"
+ user = "%[9]s"
+ }
+ caching = {
+ disabled = %[10]s
+ }
+ }`,
+ rnd,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ fmt.Sprintf("%d", origin.Port),
+ origin.Scheme,
+ origin.User,
+ fmt.Sprintf("%t", *caching.Disabled),
+ )
+}
+
+func testHyperdriveConfigUpdate(
+ rnd, id, accountId, name string, password string, origin cfv1.HyperdriveConfigOrigin, caching cfv1.HyperdriveConfigCaching,
+) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_hyperdrive_config" "%[1]s" {
+ id = "%[2]s"
+ account_id = "%[3]s"
+ name = "%[4]s"
+ origin = {
+ password = "%[5]s"
+ database = "%[6]s"
+ host = "%[7]s"
+ port = "%[8]s"
+ scheme = "%[9]s"
+ user = "%[10]s"
+ }
+ caching = {
+ disabled = %[11]s
+ }
+ }`,
+ rnd,
+ id,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ fmt.Sprintf("%d", origin.Port),
+ origin.Scheme,
+ origin.User,
+ fmt.Sprintf("%t", *caching.Disabled),
+ )
+}
+
+func testHyperdriveConfigFullCachingSettings(
rnd, accountId, name string, password string, origin cfv1.HyperdriveConfigOrigin, caching cfv1.HyperdriveConfigCaching,
) string {
return fmt.Sprintf(`
@@ -171,9 +477,92 @@ func testHyperdriveConfigConfig(
}
caching = {
disabled = %[10]s
+ max_age = %[11]s
+ stale_while_revalidate = %[12]s
+ }
+ }`,
+ rnd,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ fmt.Sprintf("%d", origin.Port),
+ origin.Scheme,
+ origin.User,
+ fmt.Sprintf("%t", *caching.Disabled),
+ fmt.Sprintf("%d", caching.MaxAge),
+ fmt.Sprintf("%d", caching.StaleWhileRevalidate),
+ )
+}
+
+func testHyperdriveOverAccessConfig(
+ rnd, accountId, name string, password string, origin cfv1.HyperdriveConfigOriginWithSecrets, caching cfv1.HyperdriveConfigCaching,
+) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_hyperdrive_config" "%[1]s" {
+ account_id = "%[2]s"
+ name = "%[3]s"
+ origin = {
+ password = "%[4]s"
+ database = "%[5]s"
+ host = "%[6]s"
+ scheme = "%[7]s"
+ user = "%[8]s"
+ access_client_id = "%[9]s"
+ access_client_secret = "%[10]s"
+ }
+ caching = {
+ disabled = %[11]s
+ }
+ }`,
+ rnd,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ origin.Scheme,
+ origin.User,
+ origin.AccessClientID,
+ origin.AccessClientSecret,
+ fmt.Sprintf("%t", *caching.Disabled),
+ )
+}
+
+func testHyperdriveOverAccessUpdate(
+ rnd, id, accountId, name string, password string, origin cfv1.HyperdriveConfigOriginWithSecrets, caching cfv1.HyperdriveConfigCaching,
+) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_hyperdrive_config" "%[1]s" {
+ id = "%[2]s"
+ account_id = "%[3]s"
+ name = "%[4]s"
+ origin = {
+ password = "%[5]s"
+ database = "%[6]s"
+ host = "%[7]s"
+ scheme = "%[8]s"
+ user = "%[9]s"
+ access_client_id = "%[10]s"
+ access_client_secret = "%[11]s"
+ }
+ caching = {
+ disabled = %[12]s
}
}`,
- rnd, accountId, name, password, origin.Database, origin.Host, fmt.Sprintf("%d", origin.Port), origin.Scheme, origin.User, fmt.Sprintf("%t", *caching.Disabled),
+ rnd,
+ id,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ origin.Scheme,
+ origin.User,
+ origin.AccessClientID,
+ origin.AccessClientSecret,
+ fmt.Sprintf("%t", *caching.Disabled),
)
}
@@ -193,6 +582,14 @@ func testHyperdriveConfigConfigMinimum(
user = "%[9]s"
}
}`,
- rnd, accountId, name, password, origin.Database, origin.Host, fmt.Sprintf("%d", origin.Port), origin.Scheme, origin.User,
+ rnd,
+ accountId,
+ name,
+ password,
+ origin.Database,
+ origin.Host,
+ fmt.Sprintf("%d", origin.Port),
+ origin.Scheme,
+ origin.User,
)
}
diff --git a/internal/framework/service/hyperdrive_config/schema.go b/internal/framework/service/hyperdrive_config/schema.go
index ab10bcb88e..0fc45e39ef 100644
--- a/internal/framework/service/hyperdrive_config/schema.go
+++ b/internal/framework/service/hyperdrive_config/schema.go
@@ -5,10 +5,14 @@ import (
"github.com/MakeNowJust/heredoc/v2"
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
func (r *HyperdriveConfigResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -53,7 +57,11 @@ func (r *HyperdriveConfigResource) Schema(ctx context.Context, req resource.Sche
},
"port": schema.Int64Attribute{
MarkdownDescription: "The port (default: 5432 for Postgres) of your origin database.",
- Required: true,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.AtLeast(0),
+ int64validator.AtMost(65535),
+ },
},
"scheme": schema.StringAttribute{
MarkdownDescription: "Specifies the URL scheme used to connect to your origin database.",
@@ -63,6 +71,22 @@ func (r *HyperdriveConfigResource) Schema(ctx context.Context, req resource.Sche
MarkdownDescription: "The user of your origin database.",
Required: true,
},
+ "access_client_id": schema.StringAttribute{
+ MarkdownDescription: "Client ID associated with the Cloudflare Access Service Token used to connect via Access.",
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("access_client_secret")),
+ stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("port")),
+ },
+ },
+ "access_client_secret": schema.StringAttribute{
+ MarkdownDescription: "Client Secret associated with the Cloudflare Access Service Token used to connect via Access.",
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("access_client_id")),
+ stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("port")),
+ },
+ },
},
},
"caching": schema.SingleNestedAttribute{
@@ -75,6 +99,23 @@ func (r *HyperdriveConfigResource) Schema(ctx context.Context, req resource.Sche
Optional: true,
Computed: true,
},
+ "max_age": schema.Int64Attribute{
+ MarkdownDescription: "Configure the `max_age` value of this Hyperdrive configuration.",
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.AtLeast(0),
+ int64validator.AtMost(3600),
+ },
+ },
+ "stale_while_revalidate": schema.Int64Attribute{
+ MarkdownDescription: "Disable caching for this Hyperdrive configuration.",
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.AlsoRequires(path.MatchRelative().AtParent().AtName("max_age")),
+ int64validator.AtLeast(0),
+ int64validator.AtMost(3600), // Max value is the value of max_age, API will reject if not
+ },
+ },
},
},
},
diff --git a/internal/framework/service/list_item/resource.go b/internal/framework/service/list_item/resource.go
index 8a4920f8d9..4195794331 100644
--- a/internal/framework/service/list_item/resource.go
+++ b/internal/framework/service/list_item/resource.go
@@ -308,7 +308,17 @@ func createListItem(ctx context.Context, client *muxclient.Client, data *ListIte
}
for _, item := range items {
- if item.Redirect.SourceUrl == searchTerm {
+ if item.Hostname != nil && item.Hostname.UrlHostname == searchTerm {
+ items = []cfv1.ListItem{item}
+ break
+ }
+
+ if item.Redirect != nil && item.Redirect.SourceUrl == searchTerm {
+ items = []cfv1.ListItem{item}
+ break
+ }
+
+ if item.IP != nil && cfv1.String(item.IP) == searchTerm {
items = []cfv1.ListItem{item}
break
}
diff --git a/internal/framework/service/list_item/resource_test.go b/internal/framework/service/list_item/resource_test.go
index dbc3736984..e1422560ab 100644
--- a/internal/framework/service/list_item/resource_test.go
+++ b/internal/framework/service/list_item/resource_test.go
@@ -433,3 +433,104 @@ func testAccCheckCloudflareHostnameRedirectWithOverlappingSourceURL(ID, name, co
}
`, ID, name, comment, accountID)
}
+
+func TestAccCloudflareListItem_WithOverlappingHostname(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ firstResource := fmt.Sprintf("cloudflare_list_item.%s_1", rnd)
+ secondResource := fmt.Sprintf("cloudflare_list_item.%s_2", rnd)
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ acctest.TestAccPreCheck_Account(t)
+ },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareHostnameWithOverlappingHostname(rnd, rnd, rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(firstResource, "hostname.#", "1"),
+ resource.TestCheckResourceAttr(firstResource, "hostname.0.url_hostname", "site1.com"),
+
+ resource.TestCheckResourceAttr(secondResource, "hostname.#", "1"),
+ resource.TestCheckResourceAttr(secondResource, "hostname.0.url_hostname", "test.site1.com"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareHostnameWithOverlappingHostname(ID, name, comment, accountID string) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_list" "%[2]s" {
+ account_id = "%[4]s"
+ name = "%[2]s"
+ description = "list named %[2]s"
+ kind = "hostname"
+ }
+
+ resource "cloudflare_list_item" "%[1]s_1" {
+ account_id = "%[4]s"
+ list_id = cloudflare_list.%[2]s.id
+ comment = "%[3]s"
+ hostname {
+ url_hostname = "site1.com"
+ }
+ }
+
+ resource "cloudflare_list_item" "%[1]s_2" {
+ account_id = "%[4]s"
+ list_id = cloudflare_list.%[2]s.id
+ comment = "%[3]s"
+ hostname {
+ url_hostname = "test.site1.com"
+ }
+ }
+ `, ID, name, comment, accountID)
+}
+
+func TestAccCloudflareListItem_IPWithOverlappingPrefix(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ firstResource := fmt.Sprintf("cloudflare_list_item.%s_1", rnd)
+ secondResource := fmt.Sprintf("cloudflare_list_item.%s_2", rnd)
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ acctest.TestAccPreCheck_Account(t)
+ },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareHostnameIPWithOverlappingPrefix(rnd, rnd, rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(firstResource, "ip", "192.0.2.10"),
+ resource.TestCheckResourceAttr(secondResource, "ip", "192.0.2.1"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareHostnameIPWithOverlappingPrefix(ID, name, comment, accountID string) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_list" "%[2]s" {
+ account_id = "%[4]s"
+ name = "%[2]s"
+ description = "list named %[2]s"
+ kind = "ip"
+ }
+
+ resource "cloudflare_list_item" "%[1]s_1" {
+ account_id = "%[4]s"
+ list_id = cloudflare_list.%[2]s.id
+ ip = "192.0.2.10"
+ }
+
+ resource "cloudflare_list_item" "%[1]s_2" {
+ account_id = "%[4]s"
+ list_id = cloudflare_list.%[2]s.id
+ ip = "192.0.2.1"
+ }
+ `, ID, name, comment, accountID)
+}
diff --git a/internal/framework/service/r2_bucket/resource_test.go b/internal/framework/service/r2_bucket/resource_test.go
index dfcc3293b8..d45ddf8a12 100644
--- a/internal/framework/service/r2_bucket/resource_test.go
+++ b/internal/framework/service/r2_bucket/resource_test.go
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
+ "regexp"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
@@ -147,6 +148,22 @@ func TestAccCloudflareR2Bucket_Minimum(t *testing.T) {
})
}
+func TestAccCloudflareR2Bucket_InvalidLocation(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareR2BucketInvalidLocation(rnd, accountID),
+ ExpectError: regexp.MustCompile("Error: Invalid Attribute Value Match"),
+ },
+ },
+ })
+}
+
func testAccCheckCloudflareR2BucketMinimum(rnd, accountID string) string {
return fmt.Sprintf(`
resource "cloudflare_r2_bucket" "%[1]s" {
@@ -163,3 +180,12 @@ func testAccCheckCloudflareR2BucketBasic(rnd, accountID string) string {
location = "ENAM"
}`, rnd, accountID)
}
+
+func testAccCheckCloudflareR2BucketInvalidLocation(rnd, accountID string) string {
+ return fmt.Sprintf(`
+ resource "cloudflare_r2_bucket" "%[1]s" {
+ account_id = "%[2]s"
+ name = "%[1]s"
+ location = "foo"
+ }`, rnd, accountID)
+}
diff --git a/internal/framework/service/r2_bucket/schema.go b/internal/framework/service/r2_bucket/schema.go
index 1bb470cc31..5be450634d 100644
--- a/internal/framework/service/r2_bucket/schema.go
+++ b/internal/framework/service/r2_bucket/schema.go
@@ -2,15 +2,21 @@ package r2_bucket
import (
"context"
+ "fmt"
"github.com/MakeNowJust/heredoc/v2"
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
+var locationHints = []string{"WNAM", "ENAM", "WEUR", "EEUR", "APAC"}
+
func (r *R2BucketResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: heredoc.Doc(`
@@ -39,10 +45,13 @@ func (r *R2BucketResource) Schema(ctx context.Context, req resource.SchemaReques
"location": schema.StringAttribute{
Optional: true,
Computed: true,
- MarkdownDescription: "The location hint of the R2 bucket.",
+ MarkdownDescription: fmt.Sprintf("The location hint of the R2 bucket. %s", utils.RenderAvailableDocumentationValuesStringSlice(locationHints)),
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
+ Validators: []validator.String{
+ stringvalidator.OneOf(locationHints...),
+ },
},
},
}
diff --git a/internal/framework/service/risk_behavior/resource.go b/internal/framework/service/risk_behavior/resource.go
index 837332b916..cd99580f46 100644
--- a/internal/framework/service/risk_behavior/resource.go
+++ b/internal/framework/service/risk_behavior/resource.go
@@ -70,7 +70,14 @@ func (r *RiskBehaviorResource) Create(ctx context.Context, req resource.CreateRe
return
}
- behaviorsSet := ConvertBehaviorsCtoT(behaviors.Behaviors)
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ _, ok := behaviorsMap[k]
+ if ok {
+ retained[k] = b
+ }
+ }
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
data.AccountID = types.StringValue(accountId)
data.Behaviors = behaviorsSet
@@ -94,13 +101,28 @@ func (r *RiskBehaviorResource) Read(ctx context.Context, req resource.ReadReques
return
}
- behaviorsSet := ConvertBehaviorsCtoT(behaviors.Behaviors)
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ if containsBehavior(data.Behaviors, k) {
+ retained[k] = b
+ }
+ }
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
data.AccountID = types.StringValue(accountId)
data.Behaviors = behaviorsSet
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
+func containsBehavior(s []RiskBehaviorBehaviorModel, n string) bool {
+ for _, a := range s {
+ if a.Name.ValueString() == n {
+ return true
+ }
+ }
+ return false
+}
+
func ConvertBehaviorsTtoC(b []RiskBehaviorBehaviorModel) (map[string]cloudflare.Behavior, error) {
behaviorsMap := map[string]cloudflare.Behavior{}
for _, b := range b {
@@ -163,7 +185,15 @@ func (r *RiskBehaviorResource) Update(ctx context.Context, req resource.UpdateRe
return
}
- behaviorsSet := ConvertBehaviorsCtoT(behaviors.Behaviors)
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ _, ok := behaviorsMap[k]
+ if ok {
+ retained[k] = b
+ }
+ }
+
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
data.AccountID = types.StringValue(accountId)
data.Behaviors = behaviorsSet
diff --git a/internal/framework/service/risk_behavior/resource_test.go b/internal/framework/service/risk_behavior/resource_test.go
index da05af51b3..f575645b81 100644
--- a/internal/framework/service/risk_behavior/resource_test.go
+++ b/internal/framework/service/risk_behavior/resource_test.go
@@ -18,8 +18,8 @@ func TestMain(m *testing.M) {
}
func init() {
- resource.AddTestSweepers("cloudflare_risk_behavior", &resource.Sweeper{
- Name: "cloudflare_risk_behavior",
+ resource.AddTestSweepers("cloudflare_zero_trust_risk_behavior", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_risk_behavior",
F: func(region string) error {
client, err := acctest.SharedV1Client()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
@@ -51,9 +51,41 @@ func init() {
})
}
+func TestAccCloudflareRiskBehavior_Partial(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ name := "cloudflare_zero_trust_risk_behavior." + rnd
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareRiskBehaviorsPartial(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "behavior.#", "1"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCloudflareRiskBehaviorsPartial(name, accountId string) string {
+ return fmt.Sprintf(`
+ resource cloudflare_zero_trust_risk_behavior %s {
+ account_id = "%s"
+ behavior {
+ name = "imp_travel"
+ enabled = true
+ risk_level = "high"
+ }
+ }`, name, accountId)
+}
+
func TestAccCloudflareRiskBehavior_Basic(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
- name := "cloudflare_risk_behavior." + rnd
+ name := "cloudflare_zero_trust_risk_behavior." + rnd
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.ParallelTest(t, resource.TestCase{
@@ -73,7 +105,7 @@ func TestAccCloudflareRiskBehavior_Basic(t *testing.T) {
func testAccCloudflareRiskBehaviors(name, accountId string) string {
return fmt.Sprintf(`
- resource cloudflare_risk_behavior %s {
+ resource cloudflare_zero_trust_risk_behavior %s {
account_id = "%s"
behavior {
name = "imp_travel"
diff --git a/internal/framework/service/risk_behavior/schema.go b/internal/framework/service/risk_behavior/schema.go
index f2856c00f0..a5dc88b606 100644
--- a/internal/framework/service/risk_behavior/schema.go
+++ b/internal/framework/service/risk_behavior/schema.go
@@ -18,6 +18,8 @@ import (
func (r *RiskBehaviorResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
+ DeprecationMessage: "`cloudflare_risk_behavior` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_risk_behavior` instead.",
+
MarkdownDescription: heredoc.Doc(`
The [Risk Behavior](https://developers.cloudflare.com/cloudflare-one/insights/risk-score/) resource allows you to configure Cloudflare Risk Behaviors for an account.
`),
diff --git a/internal/framework/service/workers_for_platforms/model.go b/internal/framework/service/workers_for_platforms_dispatch_namespace/model.go
similarity index 64%
rename from internal/framework/service/workers_for_platforms/model.go
rename to internal/framework/service/workers_for_platforms_dispatch_namespace/model.go
index 27175eac24..f73cac9006 100644
--- a/internal/framework/service/workers_for_platforms/model.go
+++ b/internal/framework/service/workers_for_platforms_dispatch_namespace/model.go
@@ -1,8 +1,8 @@
-package workers_for_platforms
+package workers_for_platforms_dispatch_namespace
import "github.com/hashicorp/terraform-plugin-framework/types"
-type WorkersForPlatformsNamespaceModel struct {
+type WorkersForPlatformsDispatchNamespaceModel struct {
AccountID types.String `tfsdk:"account_id"`
Name types.String `tfsdk:"name"`
ID types.String `tfsdk:"id"`
diff --git a/internal/framework/service/workers_for_platforms/resource.go b/internal/framework/service/workers_for_platforms_dispatch_namespace/resource.go
similarity index 64%
rename from internal/framework/service/workers_for_platforms/resource.go
rename to internal/framework/service/workers_for_platforms_dispatch_namespace/resource.go
index 9ce04a3773..17ed4e2572 100644
--- a/internal/framework/service/workers_for_platforms/resource.go
+++ b/internal/framework/service/workers_for_platforms_dispatch_namespace/resource.go
@@ -1,4 +1,4 @@
-package workers_for_platforms
+package workers_for_platforms_dispatch_namespace
import (
"context"
@@ -13,23 +13,23 @@ import (
)
// Ensure provider defined types fully satisfy framework interfaces.
-var _ resource.Resource = &WorkersForPlatformsResource{}
-var _ resource.ResourceWithImportState = &WorkersForPlatformsResource{}
+var _ resource.Resource = &WorkersForPlatformsDispatchNamespaceResource{}
+var _ resource.ResourceWithImportState = &WorkersForPlatformsDispatchNamespaceResource{}
func NewResource() resource.Resource {
- return &WorkersForPlatformsResource{}
+ return &WorkersForPlatformsDispatchNamespaceResource{}
}
-// WorkersForPlatformsResource defines the resource implementation.
-type WorkersForPlatformsResource struct {
+// WorkersForPlatformsDispatchNamespaceResource defines the resource implementation.
+type WorkersForPlatformsDispatchNamespaceResource struct {
client *muxclient.Client
}
-func (r *WorkersForPlatformsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_workers_for_platforms_namespace"
+func (r *WorkersForPlatformsDispatchNamespaceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_workers_for_platforms_dispatch_namespace"
}
-func (r *WorkersForPlatformsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+func (r *WorkersForPlatformsDispatchNamespaceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
@@ -48,8 +48,8 @@ func (r *WorkersForPlatformsResource) Configure(ctx context.Context, req resourc
r.client = client
}
-func (r *WorkersForPlatformsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data *WorkersForPlatformsNamespaceModel
+func (r *WorkersForPlatformsDispatchNamespaceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *WorkersForPlatformsDispatchNamespaceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
@@ -71,8 +71,8 @@ func (r *WorkersForPlatformsResource) Create(ctx context.Context, req resource.C
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
-func (r *WorkersForPlatformsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var data *WorkersForPlatformsNamespaceModel
+func (r *WorkersForPlatformsDispatchNamespaceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *WorkersForPlatformsDispatchNamespaceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@@ -90,8 +90,8 @@ func (r *WorkersForPlatformsResource) Read(ctx context.Context, req resource.Rea
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
-func (r *WorkersForPlatformsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var data *WorkersForPlatformsNamespaceModel
+func (r *WorkersForPlatformsDispatchNamespaceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data *WorkersForPlatformsDispatchNamespaceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
@@ -102,8 +102,8 @@ func (r *WorkersForPlatformsResource) Update(ctx context.Context, req resource.U
resp.Diagnostics.AddError("failed to update Workers for Platforms namespace", "Not implemented")
}
-func (r *WorkersForPlatformsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var data *WorkersForPlatformsNamespaceModel
+func (r *WorkersForPlatformsDispatchNamespaceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data *WorkersForPlatformsDispatchNamespaceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@@ -119,7 +119,7 @@ func (r *WorkersForPlatformsResource) Delete(ctx context.Context, req resource.D
}
}
-func (r *WorkersForPlatformsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *WorkersForPlatformsDispatchNamespaceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
idparts := strings.Split(req.ID, "/")
if len(idparts) != 2 {
resp.Diagnostics.AddError("error importing Workers for Platforms namespace", "invalid ID specified. Please specify the ID as \"account_id/name\"")
diff --git a/internal/framework/service/workers_for_platforms/resource_test.go b/internal/framework/service/workers_for_platforms_dispatch_namespace/resource_test.go
similarity index 86%
rename from internal/framework/service/workers_for_platforms/resource_test.go
rename to internal/framework/service/workers_for_platforms_dispatch_namespace/resource_test.go
index 2c89feef3b..39451a4a2e 100644
--- a/internal/framework/service/workers_for_platforms/resource_test.go
+++ b/internal/framework/service/workers_for_platforms_dispatch_namespace/resource_test.go
@@ -1,4 +1,4 @@
-package workers_for_platforms_test
+package workers_for_platforms_dispatch_namespace_test
import (
"context"
@@ -18,8 +18,8 @@ func TestMain(m *testing.M) {
}
func init() {
- resource.AddTestSweepers("cloudflare_workers_for_platforms_namespace", &resource.Sweeper{
- Name: "cloudflare_workers_for_platforms_namespace",
+ resource.AddTestSweepers("cloudflare_workers_for_platforms_dispatch_namespace", &resource.Sweeper{
+ Name: "cloudflare_workers_for_platforms_dispatch_namespace",
F: func(region string) error {
client, err := acctest.SharedV1Client()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
@@ -49,7 +49,7 @@ func init() {
func TestAccCloudflareWorkersForPlatforms_NamespaceManagement(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
- resourceName := "cloudflare_workers_for_platforms_namespace." + rnd
+ resourceName := "cloudflare_workers_for_platforms_dispatch_namespace." + rnd
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.TestAccPreCheck(t) },
@@ -74,7 +74,7 @@ func TestAccCloudflareWorkersForPlatforms_NamespaceManagement(t *testing.T) {
func testAccCheckCloudflareWorkersForPlatformsNamespaceManagement(rnd, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_workers_for_platforms_namespace" "%[1]s" {
+ resource "cloudflare_workers_for_platforms_dispatch_namespace" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
}`, rnd, accountID)
@@ -83,8 +83,8 @@ func testAccCheckCloudflareWorkersForPlatformsNamespaceManagement(rnd, accountID
func TestAccCloudflareWorkersForPlatforms_UploadUserWorker(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
- resourceName := "cloudflare_workers_for_platforms_namespace." + rnd
- workerResource := "cloudflare_worker_script.script_" + rnd
+ resourceName := "cloudflare_workers_for_platforms_dispatch_namespace." + rnd
+ workerResource := "cloudflare_workers_script.script_" + rnd
scriptContent := `<\" or \"zone/\""
+ if len(attributes) != 2 {
+ resp.Diagnostics.AddError("error importing Access Mutual TLS Hostname Settings", fmt.Sprintf(invalidIDMessage, req.ID))
+ return
+ }
+
+ identifierType, identifierID := attributes[0], attributes[1]
+
+ if !(identifierType == "zone" || identifierType == "account") {
+ resp.Diagnostics.AddError("invalid id specified", fmt.Sprintf(invalidIDMessage, req.ID))
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("Importing Cloudflare Access Mutual TLS Hostname Settings: for %s %s", identifierType, identifierID))
+
+ schemaIdentifierName := "account_id"
+ if identifierType == "zone" {
+ schemaIdentifierName = "zone_id"
+ }
+ resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(schemaIdentifierName), identifierID)...)
+}
+
+func buildAccessMutualTLSHostnameSettingsModel(settings []cfv1.AccessMutualTLSHostnameSettings, zoneID, accountID basetypes.StringValue) *ZeroTrustAccessMutualTLSHostnameSettingsModel {
+ model := &ZeroTrustAccessMutualTLSHostnameSettingsModel{
+ ZoneID: zoneID,
+ AccountID: accountID,
+ }
+ for _, setting := range settings {
+ model.Settings = append(model.Settings, Settings{
+ Hostname: types.StringValue(setting.Hostname),
+ ChinaNetwork: types.BoolValue(cfv1.Bool(setting.ChinaNetwork)),
+ ClientCertificateForwarding: types.BoolValue(cfv1.Bool(setting.ClientCertificateForwarding)),
+ })
+ }
+ return model
+}
+
+func getIdentifier(data *ZeroTrustAccessMutualTLSHostnameSettingsModel) *cfv1.ResourceContainer {
+ accountID := data.AccountID
+ zoneID := data.ZoneID
+
+ var identifier *cfv1.ResourceContainer
+ if accountID.ValueString() != "" {
+ identifier = cfv1.AccountIdentifier(accountID.ValueString())
+ } else {
+ identifier = cfv1.ZoneIdentifier(zoneID.ValueString())
+ }
+
+ return identifier
+}
diff --git a/internal/framework/service/zero_trust_access_mtls_hostname_settings/resource_test.go b/internal/framework/service/zero_trust_access_mtls_hostname_settings/resource_test.go
new file mode 100644
index 0000000000..cc4345a7bb
--- /dev/null
+++ b/internal/framework/service/zero_trust_access_mtls_hostname_settings/resource_test.go
@@ -0,0 +1,123 @@
+package zero_trust_access_mtls_hostname_settings_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ cfv1 "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+func init() {
+ resource.AddTestSweepers("cloudflare_zero_trust_access_mtls_hostname_settings", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_mtls_hostname_settings",
+ F: func(region string) error {
+ ctx := context.Background()
+
+ client, clientErr := acctest.SharedV1Client()
+ if clientErr != nil {
+ return fmt.Errorf("Failed to create Cloudflare client: %w", clientErr)
+ }
+
+ deletedSettings := cfv1.UpdateAccessMutualTLSHostnameSettingsParams{
+ Settings: []cfv1.AccessMutualTLSHostnameSettings{},
+ }
+
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+ _, err := client.UpdateAccessMutualTLSHostnameSettings(ctx, cfv1.AccountIdentifier(accountID), deletedSettings)
+ if err != nil {
+ return fmt.Errorf("Failed to fetch Cloudflare Access Mutual TLS hostname settings: %w", err)
+ }
+
+ zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
+ _, err = client.UpdateAccessMutualTLSHostnameSettings(ctx, cfv1.ZoneIdentifier(zoneID), deletedSettings)
+ if err != nil {
+ return fmt.Errorf("Failed to delete Cloudflare Access Mutual TLS hostname settings: %w", err)
+ }
+
+ return nil
+ },
+ })
+}
+
+func TestAccCloudflareAccessMutualTLSHostnameSettings_Simple(t *testing.T) {
+ // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
+ // service does not yet support the API tokens and it results in
+ // misleading state error messages.
+ if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
+ t.Setenv("CLOUDFLARE_API_TOKEN", "")
+ }
+
+ rnd := utils.GenerateRandomResourceName()
+ name := fmt.Sprintf("cloudflare_zero_trust_access_mtls_hostname_settings.%s", rnd)
+ domain := os.Getenv("CLOUDFLARE_DOMAIN")
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ acctest.TestAccPreCheck(t)
+ acctest.TestAccPreCheck_Account(t)
+ },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ CheckDestroy: testAccCheckCloudflareAccessMutualTLSHostnameSettingsDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccessMutualTLSHostnameSettingsConfig(rnd, cfv1.AccountIdentifier(accountID), domain),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "settings.0.hostname", domain),
+ resource.TestCheckResourceAttr(name, "settings.0.china_network", "false"),
+ resource.TestCheckResourceAttr(name, "settings.0.client_certificate_forwarding", "true"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudflareAccessMutualTLSHostnameSettingsDestroy(s *terraform.State) error {
+ client, err := acctest.SharedV1Client()
+ if err != nil {
+ return fmt.Errorf("Failed to create Cloudflare client: %w", err)
+ }
+
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "cloudflare_zero_trust_access_mtls_hostname_settings" {
+ continue
+ }
+
+ if rs.Primary.Attributes[consts.ZoneIDSchemaKey] != "" {
+ settings, _ := client.GetAccessMutualTLSHostnameSettings(context.Background(), cfv1.ZoneIdentifier(rs.Primary.Attributes[consts.ZoneIDSchemaKey]))
+ if len(settings) != 0 {
+ return fmt.Errorf("AccessMutualTLSHostnameSettings still exists")
+ }
+ }
+
+ if rs.Primary.Attributes[consts.AccountIDSchemaKey] != "" {
+ settings, _ := client.GetAccessMutualTLSHostnameSettings(context.Background(), cfv1.AccountIdentifier(rs.Primary.Attributes[consts.AccountIDSchemaKey]))
+ if len(settings) != 0 {
+ return fmt.Errorf("AccessMutualTLSHostnameSettings still exists")
+ }
+ }
+ }
+
+ return nil
+}
+
+func testAccessMutualTLSHostnameSettingsConfig(rnd string, identifier *cfv1.ResourceContainer, domain string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_access_mtls_hostname_settings" "%[1]s" {
+ %[2]s_id = "%[3]s"
+ settings {
+ hostname = "%[4]s"
+ client_certificate_forwarding = true
+ china_network = false
+ }
+}
+`, rnd, identifier.Type, identifier.Identifier, domain)
+}
diff --git a/internal/framework/service/zero_trust_access_mtls_hostname_settings/schema.go b/internal/framework/service/zero_trust_access_mtls_hostname_settings/schema.go
new file mode 100644
index 0000000000..b02d75b3bf
--- /dev/null
+++ b/internal/framework/service/zero_trust_access_mtls_hostname_settings/schema.go
@@ -0,0 +1,62 @@
+package zero_trust_access_mtls_hostname_settings
+
+import (
+ "context"
+
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+)
+
+func (r *ZeroTrustAccessMutualTLSHostnameSettingsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Description: "Provides a Cloudflare Access Mutual TLS Certificate Settings resource.",
+ Attributes: map[string]schema.Attribute{
+ consts.AccountIDSchemaKey: schema.StringAttribute{
+ Description: consts.AccountIDSchemaDescription,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.ConflictsWith(
+ path.Expression(path.MatchRoot(consts.ZoneIDSchemaKey)),
+ ),
+ },
+ },
+ consts.ZoneIDSchemaKey: schema.StringAttribute{
+ Description: consts.ZoneIDSchemaDescription,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.ConflictsWith(
+ path.Expression(path.MatchRoot(consts.AccountIDSchemaKey)),
+ ),
+ },
+ },
+ },
+ Blocks: map[string]schema.Block{
+ "settings": schema.ListNestedBlock{
+ NestedObject: schema.NestedBlockObject{
+ Attributes: map[string]schema.Attribute{
+ "hostname": schema.StringAttribute{
+ Required: true,
+ Description: "The hostname that these settings apply to.",
+ },
+ "china_network": schema.BoolAttribute{
+ Optional: true,
+ Description: "Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled.",
+ },
+ "client_certificate_forwarding": schema.BoolAttribute{
+ Optional: true,
+ Description: "Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin.",
+ },
+ },
+ },
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ },
+ }
+}
diff --git a/internal/framework/service/zero_trust_risk_behavior/model.go b/internal/framework/service/zero_trust_risk_behavior/model.go
new file mode 100644
index 0000000000..92b016dd31
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_behavior/model.go
@@ -0,0 +1,14 @@
+package zero_trust_risk_behavior
+
+import "github.com/hashicorp/terraform-plugin-framework/types"
+
+type ZeroTrustRiskBehaviorModel struct {
+ AccountID types.String `tfsdk:"account_id"`
+ Behaviors []ZeroTrustRiskBehaviorBehaviorModel `tfsdk:"behavior"`
+}
+
+type ZeroTrustRiskBehaviorBehaviorModel struct {
+ Enabled types.Bool `tfsdk:"enabled"`
+ Name types.String `tfsdk:"name"`
+ RiskLevel types.String `tfsdk:"risk_level"`
+}
diff --git a/internal/framework/service/zero_trust_risk_behavior/resource.go b/internal/framework/service/zero_trust_risk_behavior/resource.go
new file mode 100644
index 0000000000..b83f7710a1
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_behavior/resource.go
@@ -0,0 +1,231 @@
+package zero_trust_risk_behavior
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces.
+var _ resource.Resource = &ZeroTrustRiskBehaviorResource{}
+
+func NewResource() resource.Resource {
+ return &ZeroTrustRiskBehaviorResource{}
+}
+
+// ZeroTrustRiskBehaviorResource defines the resource implementation.
+type ZeroTrustRiskBehaviorResource struct {
+ client *muxclient.Client
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_zero_trust_risk_behavior"
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*muxclient.Client)
+
+ if !ok {
+ resp.Diagnostics.AddError(
+ "unexpected resource configure type",
+ fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+
+ return
+ }
+
+ r.client = client
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *ZeroTrustRiskBehaviorModel
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ accountId := data.AccountID.ValueString()
+
+ behaviorsMap, err := ConvertBehaviorsTtoC(data.Behaviors)
+ if err != nil {
+ resp.Diagnostics.AddError("invalid risk level", err.Error())
+ return
+ }
+
+ behaviors, err := r.client.V1.UpdateBehaviors(ctx, accountId,
+ cloudflare.Behaviors{Behaviors: behaviorsMap},
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed to create risk behaviors", err.Error())
+ return
+ }
+
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ _, ok := behaviorsMap[k]
+ if ok {
+ retained[k] = b
+ }
+ }
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
+
+ data.AccountID = types.StringValue(accountId)
+ data.Behaviors = behaviorsSet
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *ZeroTrustRiskBehaviorModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ accountId := data.AccountID.ValueString()
+
+ behaviors, err := r.client.V1.Behaviors(ctx, accountId)
+ if err != nil {
+ resp.Diagnostics.AddError("failed reading risk behaviors", err.Error())
+ return
+ }
+
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ if containsBehavior(data.Behaviors, k) {
+ retained[k] = b
+ }
+ }
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
+
+ data.AccountID = types.StringValue(accountId)
+ data.Behaviors = behaviorsSet
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func containsBehavior(s []ZeroTrustRiskBehaviorBehaviorModel, n string) bool {
+ for _, a := range s {
+ if a.Name.ValueString() == n {
+ return true
+ }
+ }
+ return false
+}
+
+func ConvertBehaviorsTtoC(b []ZeroTrustRiskBehaviorBehaviorModel) (map[string]cloudflare.Behavior, error) {
+ behaviorsMap := map[string]cloudflare.Behavior{}
+ for _, b := range b {
+ riskLevel, err := cloudflare.RiskLevelFromString(b.RiskLevel.ValueString())
+ if err != nil {
+ return nil, err
+ }
+
+ enabled := b.Enabled.ValueBool()
+
+ behavior := cloudflare.Behavior{
+ Enabled: &enabled,
+ RiskLevel: *riskLevel,
+ }
+
+ behaviorsMap[b.Name.ValueString()] = behavior
+ }
+
+ return behaviorsMap, nil
+}
+
+func ConvertBehaviorsCtoT(b map[string]cloudflare.Behavior) []ZeroTrustRiskBehaviorBehaviorModel {
+ behaviorsSet := []ZeroTrustRiskBehaviorBehaviorModel{}
+
+ for k, b := range b {
+ behavior := ZeroTrustRiskBehaviorBehaviorModel{
+ Enabled: types.BoolPointerValue(b.Enabled),
+ Name: types.StringValue(k),
+ RiskLevel: types.StringValue(fmt.Sprint(b.RiskLevel)),
+ }
+
+ behaviorsSet = append(behaviorsSet, behavior)
+ }
+
+ return behaviorsSet
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data *ZeroTrustRiskBehaviorModel
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ accountId := data.AccountID.ValueString()
+
+ behaviorsMap, err := ConvertBehaviorsTtoC(data.Behaviors)
+ if err != nil {
+ resp.Diagnostics.AddError("invalid risk level", err.Error())
+ return
+ }
+
+ behaviors, err := r.client.V1.UpdateBehaviors(ctx, accountId,
+ cloudflare.Behaviors{Behaviors: behaviorsMap},
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed to update risk behaviors", err.Error())
+ return
+ }
+
+ retained := map[string]cloudflare.Behavior{}
+ for k, b := range behaviors.Behaviors {
+ _, ok := behaviorsMap[k]
+ if ok {
+ retained[k] = b
+ }
+ }
+
+ behaviorsSet := ConvertBehaviorsCtoT(retained)
+
+ data.AccountID = types.StringValue(accountId)
+ data.Behaviors = behaviorsSet
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *ZeroTrustRiskBehaviorResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data *ZeroTrustRiskBehaviorModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ // tflog.Debug(ctx, "Resetting all zero trust risk behaviors to enabled: false, risk_level: low")
+
+ behaviors, err := r.client.V1.Behaviors(ctx, data.AccountID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("failed to get risk behaviors", err.Error())
+ return
+ }
+
+ // set all risk behavior values to false/low before running update
+ for _, behavior := range behaviors.Behaviors {
+ behavior.Enabled = cloudflare.BoolPtr(false)
+ behavior.RiskLevel = cloudflare.Low
+ }
+
+ _, err = r.client.V1.UpdateBehaviors(ctx, data.AccountID.ValueString(), behaviors)
+ if err != nil {
+ resp.Diagnostics.AddError("failed to reset risk behaviors", err.Error())
+ return
+ }
+}
diff --git a/internal/framework/service/zero_trust_risk_behavior/resource_test.go b/internal/framework/service/zero_trust_risk_behavior/resource_test.go
new file mode 100644
index 0000000000..55cb83afc9
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_behavior/resource_test.go
@@ -0,0 +1,121 @@
+package zero_trust_risk_behavior_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestMain(m *testing.M) {
+ resource.TestMain(m)
+}
+
+func init() {
+ resource.AddTestSweepers("cloudflare_zero_trust_risk_behavior", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_risk_behavior",
+ F: func(region string) error {
+ client, err := acctest.SharedV1Client()
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ if err != nil {
+ return fmt.Errorf("error establishing client: %w", err)
+ }
+
+ ctx := context.Background()
+
+ behaviors, err := client.Behaviors(ctx, accountID)
+ if err != nil {
+ return fmt.Errorf("failed to get risk behaviors: %w", err)
+ }
+
+ // set all risk behavior values to false/low before running update
+ for _, behavior := range behaviors.Behaviors {
+ behavior.Enabled = cloudflare.BoolPtr(false)
+ behavior.RiskLevel = cloudflare.Low
+ }
+
+ _, err = client.UpdateBehaviors(ctx, accountID, behaviors)
+ if err != nil {
+ return fmt.Errorf("failed to reset risk behaviors: %w", err)
+ }
+
+ return nil
+ },
+ })
+}
+
+func TestAccCloudflareRiskBehavior_Partial(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ name := "cloudflare_zero_trust_risk_behavior." + rnd
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareRiskBehaviorsPartial(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "behavior.#", "1"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCloudflareRiskBehaviorsPartial(name, accountId string) string {
+ return fmt.Sprintf(`
+ resource cloudflare_zero_trust_risk_behavior %s {
+ account_id = "%s"
+ behavior {
+ name = "imp_travel"
+ enabled = true
+ risk_level = "high"
+ }
+ }`, name, accountId)
+}
+
+func TestAccCloudflareRiskBehavior_Basic(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ name := "cloudflare_zero_trust_risk_behavior." + rnd
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareRiskBehaviors(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "behavior.#", "2"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCloudflareRiskBehaviors(name, accountId string) string {
+ return fmt.Sprintf(`
+ resource cloudflare_zero_trust_risk_behavior %s {
+ account_id = "%s"
+ behavior {
+ name = "imp_travel"
+ enabled = true
+ risk_level = "high"
+ }
+ behavior {
+ name = "high_dlp"
+ enabled = true
+ risk_level = "medium"
+ }
+ }`, name, accountId)
+}
diff --git a/internal/framework/service/zero_trust_risk_behavior/schema.go b/internal/framework/service/zero_trust_risk_behavior/schema.go
new file mode 100644
index 0000000000..2c4a67e592
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_behavior/schema.go
@@ -0,0 +1,65 @@
+package zero_trust_risk_behavior
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/MakeNowJust/heredoc/v2"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+)
+
+func (r *ZeroTrustRiskBehaviorResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: heredoc.Doc(`
+ The [Risk Behavior](https://developers.cloudflare.com/cloudflare-one/insights/risk-score/) resource allows you to configure Cloudflare Risk Behaviors for an account.
+ `),
+
+ Attributes: map[string]schema.Attribute{
+ consts.AccountIDSchemaKey: schema.StringAttribute{
+ MarkdownDescription: consts.AccountIDSchemaDescription,
+ Required: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ },
+
+ Blocks: map[string]schema.Block{
+
+ "behavior": schema.SetNestedBlock{
+ MarkdownDescription: "Zero Trust risk behaviors configured on this account",
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
+ setvalidator.IsRequired(),
+ },
+ NestedObject: schema.NestedBlockObject{
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of this risk behavior type",
+ },
+ "enabled": schema.BoolAttribute{
+ Required: true,
+ MarkdownDescription: "Whether this risk behavior type is enabled.",
+ },
+ "risk_level": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: fmt.Sprintf("Risk level. %s", utils.RenderAvailableDocumentationValuesStringSlice([]string{"low", "medium", "high"})),
+ Validators: []validator.String{
+ stringvalidator.OneOf("low", "medium", "high"),
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/internal/framework/service/zero_trust_risk_score_integration/model.go b/internal/framework/service/zero_trust_risk_score_integration/model.go
new file mode 100644
index 0000000000..bb10eb62d9
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_score_integration/model.go
@@ -0,0 +1,15 @@
+package zero_trust_risk_score_integration
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type RiskScoreIntegrationModel struct {
+ AccountID types.String `tfsdk:"account_id"`
+ ID types.String `tfsdk:"id"`
+ IntegrationType types.String `tfsdk:"integration_type"`
+ TenantUrl types.String `tfsdk:"tenant_url"`
+ ReferenceID types.String `tfsdk:"reference_id"`
+ Active types.Bool `tfsdk:"active"`
+ WellKnownUrl types.String `tfsdk:"well_known_url"`
+}
diff --git a/internal/framework/service/zero_trust_risk_score_integration/resource.go b/internal/framework/service/zero_trust_risk_score_integration/resource.go
new file mode 100644
index 0000000000..c19620293d
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_score_integration/resource.go
@@ -0,0 +1,186 @@
+package zero_trust_risk_score_integration
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces.
+var _ resource.Resource = &RiskScoreIntegrationResource{}
+
+func NewResource() resource.Resource {
+ return &RiskScoreIntegrationResource{}
+}
+
+// RiskScoreIntegrationResource defines the resource implementation.
+type RiskScoreIntegrationResource struct {
+ client *muxclient.Client
+}
+
+func (r *RiskScoreIntegrationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_zero_trust_risk_score_integration"
+}
+
+func (r *RiskScoreIntegrationResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*muxclient.Client)
+
+ if !ok {
+ resp.Diagnostics.AddError(
+ "unexpected resource configure type",
+ fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+ )
+
+ return
+ }
+
+ r.client = client
+}
+
+func (r *RiskScoreIntegrationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *RiskScoreIntegrationModel
+
+ // Read Terraform plan data into the model.
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ // When an integration is created, is it active
+ if !data.Active.ValueBool() {
+ resp.Diagnostics.AddError("failed to create risk score integration", "integration must be created with active=true")
+ return
+ }
+
+ accountID := data.AccountID.ValueString()
+
+ integration, err := r.client.V1.CreateRiskScoreIntegration(ctx, cloudflare.AccountIdentifier(accountID),
+ cloudflare.RiskScoreIntegrationCreateRequest{
+ IntegrationType: data.IntegrationType.ValueString(),
+ TenantUrl: data.TenantUrl.ValueString(),
+ ReferenceID: data.ReferenceID.ValueString(),
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed to create risk score integration", err.Error())
+ return
+ }
+
+ data.ID = types.StringValue(integration.ID)
+ data.ReferenceID = types.StringValue(integration.ReferenceID)
+ data.Active = types.BoolPointerValue(integration.Active)
+ data.WellKnownUrl = types.StringValue(integration.WellKnownUrl)
+ // Save state
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *RiskScoreIntegrationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *RiskScoreIntegrationModel
+
+ // Read Terraform state into the model.
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("Preparing to read Risk Score Integration: %+v", data))
+
+ accountID := data.AccountID.ValueString()
+
+ integration, err := r.client.V1.GetRiskScoreIntegration(ctx, cloudflare.AccountIdentifier(accountID), data.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("failed reading risk score integration", err.Error())
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("Read Risk Score Integration: %+v", data))
+
+ data.IntegrationType = types.StringValue(integration.IntegrationType)
+ data.TenantUrl = types.StringValue(integration.TenantUrl)
+ data.ReferenceID = types.StringValue(integration.ReferenceID)
+ data.Active = types.BoolPointerValue(integration.Active)
+ data.WellKnownUrl = types.StringValue(integration.WellKnownUrl)
+ // Save state
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *RiskScoreIntegrationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var plan_data *RiskScoreIntegrationModel
+ var state_data *RiskScoreIntegrationModel
+
+ // Read Terraform state & plan data into the model.
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &plan_data)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state_data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ accountID := plan_data.AccountID.ValueString()
+
+ tflog.Debug(ctx, fmt.Sprintf("Updating Risk Score Integration from struct: %+v", plan_data))
+
+ integration, err := r.client.V1.UpdateRiskScoreIntegration(ctx, cloudflare.AccountIdentifier(accountID), state_data.ID.ValueString(),
+ cloudflare.RiskScoreIntegrationUpdateRequest{
+ IntegrationType: plan_data.IntegrationType.ValueString(),
+ TenantUrl: plan_data.TenantUrl.ValueString(),
+ ReferenceID: plan_data.ReferenceID.ValueString(),
+ Active: plan_data.Active.ValueBoolPointer(),
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("failed updating risk score integration", err.Error())
+ return
+ }
+
+ plan_data.ID = types.StringValue(integration.ID)
+ plan_data.ReferenceID = types.StringValue(integration.ReferenceID)
+ plan_data.WellKnownUrl = types.StringValue(integration.WellKnownUrl)
+ // Save state
+ resp.Diagnostics.Append(resp.State.Set(ctx, &plan_data)...)
+}
+
+func (r *RiskScoreIntegrationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data *RiskScoreIntegrationModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ accountID := data.AccountID.ValueString()
+
+ err := r.client.V1.DeleteRiskScoreIntegration(ctx, cloudflare.AccountIdentifier(accountID), data.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("failed to delete risk score integration", err.Error())
+ return
+ }
+
+ // Delete state
+ // We don't call "resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)"
+ // This means that the state does not get set (and is deleted)
+}
+
+func (r *RiskScoreIntegrationResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ idparts := strings.Split(req.ID, "/")
+ if len(idparts) != 2 {
+ resp.Diagnostics.AddError("error importing Risk Score Integration", "invalid ID specified. Please specify the ID as \"account_id/integration_id\"")
+ return
+ }
+ resp.Diagnostics.Append(resp.State.SetAttribute(
+ ctx, path.Root("account_id"), idparts[0],
+ )...)
+ resp.Diagnostics.Append(resp.State.SetAttribute(
+ ctx, path.Root("id"), idparts[1],
+ )...)
+}
diff --git a/internal/framework/service/zero_trust_risk_score_integration/resource_test.go b/internal/framework/service/zero_trust_risk_score_integration/resource_test.go
new file mode 100644
index 0000000000..9f7b12eb2f
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_score_integration/resource_test.go
@@ -0,0 +1,102 @@
+package zero_trust_risk_score_integration_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/cloudflare/cloudflare-go"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/utils"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestMain(m *testing.M) {
+ resource.TestMain(m)
+}
+
+func init() {
+ resource.AddTestSweepers("cloudflare_zero_trust_risk_score_integration", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_risk_score_integration",
+ F: func(region string) error {
+ client, err := acctest.SharedV1Client()
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ if err != nil {
+ return fmt.Errorf("error establishing client: %w", err)
+ }
+
+ ctx := context.Background()
+
+ integrations, err := client.ListRiskScoreIntegrations(ctx, cloudflare.AccountIdentifier(accountID), cloudflare.ListRiskScoreIntegrationParams{})
+ if err != nil {
+ return fmt.Errorf("failed to get risk score integrations: %w", err)
+ }
+
+ // Clean up old integrations
+ for _, integration := range integrations {
+ err := client.DeleteRiskScoreIntegration(ctx, cloudflare.AccountIdentifier(accountID), integration.ID)
+ if err != nil {
+ return fmt.Errorf("failed to delete risk score integration: %w", err)
+ }
+ }
+
+ return nil
+ },
+ })
+}
+
+func TestAccCloudflareRiskScoreIntegration_Basic(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ name := "cloudflare_zero_trust_risk_score_integration." + rnd
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+ resource cloudflare_zero_trust_risk_score_integration %s {
+ account_id = "%s"
+ integration_type = "Okta"
+ tenant_url = "https://test-tenant.okta.com"
+ }`, rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "integration_type", "Okta"),
+ resource.TestCheckResourceAttr(name, "tenant_url", "https://test-tenant.okta.com"),
+ resource.TestCheckResourceAttr(name, "active", "true"), // Test function uses the stringified version for comparison
+ ),
+ },
+ },
+ })
+}
+
+func TestAccCloudflareRiskScoreIntegration_Reference_ID(t *testing.T) {
+ rnd := utils.GenerateRandomResourceName()
+ name := "cloudflare_zero_trust_risk_score_integration." + rnd
+ accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { acctest.TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+ resource cloudflare_zero_trust_risk_score_integration %s {
+ account_id = "%s"
+ integration_type = "Okta"
+ tenant_url = "https://test-tenant.okta.com"
+ reference_id = "58ee8f00-f28a-4b09-b955-93f7c557bd43"
+ }`, rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "reference_id", "58ee8f00-f28a-4b09-b955-93f7c557bd43"),
+ ),
+ },
+ },
+ })
+}
diff --git a/internal/framework/service/zero_trust_risk_score_integration/schema.go b/internal/framework/service/zero_trust_risk_score_integration/schema.go
new file mode 100644
index 0000000000..f4bdbffaba
--- /dev/null
+++ b/internal/framework/service/zero_trust_risk_score_integration/schema.go
@@ -0,0 +1,58 @@
+package zero_trust_risk_score_integration
+
+import (
+ "context"
+
+ "github.com/MakeNowJust/heredoc/v2"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+)
+
+func (r *RiskScoreIntegrationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: heredoc.Doc(`
+ The [Risk Score Integration](https://developers.cloudflare.com/cloudflare-one/insights/risk-score/#send-risk-score-to-okta) resource allows you to transmit changes in User Risk Score to a specified vendor such as Okta.
+ `),
+
+ Attributes: map[string]schema.Attribute{
+ consts.AccountIDSchemaKey: schema.StringAttribute{
+ MarkdownDescription: consts.AccountIDSchemaDescription,
+ Required: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ consts.IDSchemaKey: schema.StringAttribute{
+ MarkdownDescription: consts.IDSchemaDescription,
+ Computed: true,
+ },
+ "integration_type": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "The type of integration, e.g. 'Okta'. Full list of allowed values can be found here: https://developers.cloudflare.com/api/operations/dlp-zt-risk-score-integration-create#request-body",
+ },
+ "tenant_url": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "The base url of the tenant, e.g. 'https://tenant.okta.com'. Must be your Okta Tenant URL and not your custom domain.",
+ },
+ "reference_id": schema.StringAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "A reference id that can be supplied by the client. Currently this should be set to the Access-Okta IDP ID (a UUIDv4). If omitted, a random UUIDv4 is used. https://developers.cloudflare.com/api/operations/access-identity-providers-get-an-access-identity-provider",
+ },
+ "active": schema.BoolAttribute{
+ Optional: true,
+ Computed: true,
+ Default: booldefault.StaticBool(true),
+ MarkdownDescription: "Whether this integration is enabled. If disabled, no risk changes will be exported to the third-party.",
+ },
+ "well_known_url": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "The URL for the Shared Signals Framework configuration, e.g. '/.well-known/sse-configuration/{integration_uuid}/'. https://openid.net/specs/openid-sse-framework-1_0.html#rfc.section.6.2.1",
+ },
+ },
+ }
+}
diff --git a/internal/sdkv2provider/data_source_access_application.go b/internal/sdkv2provider/data_source_access_application.go
index 4d1dcbf88c..1b6728040b 100644
--- a/internal/sdkv2provider/data_source_access_application.go
+++ b/internal/sdkv2provider/data_source_access_application.go
@@ -11,6 +11,47 @@ import (
)
func dataSourceCloudflareAccessApplication() *schema.Resource {
+ return &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ consts.AccountIDSchemaKey: {
+ Description: consts.AccountIDSchemaDescription,
+ Type: schema.TypeString,
+ Optional: true,
+ ExactlyOneOf: []string{consts.ZoneIDSchemaKey, consts.AccountIDSchemaKey},
+ },
+ consts.ZoneIDSchemaKey: {
+ Description: consts.ZoneIDSchemaDescription,
+ Type: schema.TypeString,
+ Optional: true,
+ ExactlyOneOf: []string{consts.ZoneIDSchemaKey, consts.AccountIDSchemaKey},
+ },
+ "name": {
+ Description: "Friendly name of the Access Application.",
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ExactlyOneOf: []string{"name", "domain"},
+ },
+ "domain": {
+ Description: "The primary hostname and path that Access will secure.",
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ExactlyOneOf: []string{"name", "domain"},
+ },
+ "aud": {
+ Description: "Application Audience (AUD) Tag of the application.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ Description: "Use this data source to lookup a single [Access Application](https://developers.cloudflare.com/cloudflare-one/applications/)",
+ ReadContext: dataSourceCloudflareAccessApplicationRead,
+ DeprecationMessage: "`cloudflare_access_application` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_application` instead.",
+ }
+}
+
+func dataSourceCloudflareZeroTrustAccessApplication() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
consts.AccountIDSchemaKey: {
diff --git a/internal/sdkv2provider/data_source_access_application_test.go b/internal/sdkv2provider/data_source_access_application_test.go
index ddab26eb9c..e7cd1acbdc 100644
--- a/internal/sdkv2provider/data_source_access_application_test.go
+++ b/internal/sdkv2provider/data_source_access_application_test.go
@@ -11,7 +11,7 @@ import (
func TestAccCloudflareAccessApplicationDataSource_AccountName(t *testing.T) {
rnd := generateRandomResourceName()
- name := "data.cloudflare_access_application." + rnd
+ name := "data.cloudflare_zero_trust_access_application." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@@ -32,23 +32,23 @@ func TestAccCloudflareAccessApplicationDataSource_AccountName(t *testing.T) {
func testAccCheckCloudflareAccessApplicationAccountName(accountID, name, domain string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
}
- data "cloudflare_access_application" "%[1]s" {
+ data "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
- depends_on = [cloudflare_access_application.%[1]s]
+ depends_on = [cloudflare_zero_trust_access_application.%[1]s]
}
`, name, accountID, domain)
}
func TestAccCloudflareAccessApplicationDataSource_AccountDomain(t *testing.T) {
rnd := generateRandomResourceName()
- name := "data.cloudflare_access_application." + rnd
+ name := "data.cloudflare_zero_trust_access_application." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@@ -69,23 +69,23 @@ func TestAccCloudflareAccessApplicationDataSource_AccountDomain(t *testing.T) {
func testAccCheckCloudflareAccessApplicationAccountDomain(accountID, name, domain string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
}
- data "cloudflare_access_application" "%[1]s" {
+ data "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
domain = "%[1]s.%[3]s"
- depends_on = [cloudflare_access_application.%[1]s]
+ depends_on = [cloudflare_zero_trust_access_application.%[1]s]
}
`, name, accountID, domain)
}
func TestAccCloudflareAccessApplicationDataSource_ZoneName(t *testing.T) {
rnd := generateRandomResourceName()
- name := "data.cloudflare_access_application." + rnd
+ name := "data.cloudflare_zero_trust_access_application." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@@ -106,23 +106,23 @@ func TestAccCloudflareAccessApplicationDataSource_ZoneName(t *testing.T) {
func testAccCheckCloudflareAccessApplicationZoneName(zoneID, name, domain string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
}
- data "cloudflare_access_application" "%[1]s" {
+ data "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
- depends_on = [cloudflare_access_application.%[1]s]
+ depends_on = [cloudflare_zero_trust_access_application.%[1]s]
}
`, name, zoneID, domain)
}
func TestAccCloudflareAccessApplicationDataSource_ZoneDomain(t *testing.T) {
rnd := generateRandomResourceName()
- name := "data.cloudflare_access_application." + rnd
+ name := "data.cloudflare_zero_trust_access_application." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@@ -143,16 +143,16 @@ func TestAccCloudflareAccessApplicationDataSource_ZoneDomain(t *testing.T) {
func testAccCheckCloudflareAccessApplicationZoneDomain(zoneID, name, domain string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
}
- data "cloudflare_access_application" "%[1]s" {
+ data "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
domain = "%[1]s.%[3]s"
- depends_on = [cloudflare_access_application.%[1]s]
+ depends_on = [cloudflare_zero_trust_access_application.%[1]s]
}
`, name, zoneID, domain)
}
diff --git a/internal/sdkv2provider/data_source_access_identity_provider.go b/internal/sdkv2provider/data_source_access_identity_provider.go
index 8bff98c76d..26ca141361 100644
--- a/internal/sdkv2provider/data_source_access_identity_provider.go
+++ b/internal/sdkv2provider/data_source_access_identity_provider.go
@@ -10,6 +10,15 @@ import (
)
func dataSourceCloudflareAccessIdentityProvider() *schema.Resource {
+ return &schema.Resource{
+ Schema: dataSourceCloudflareAccessIdentityProviderSchema(),
+ ReadContext: dataSourceCloudflareAccessIdentityProviderRead,
+ Description: "Use this data source to lookup a single [Access Identity Provider](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration) by name.",
+ DeprecationMessage: "`cloudflare_access_identity_provider` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_identity_provider` instead.",
+ }
+}
+
+func dataSourceCloudflareZeroTrustAccessIdentityProvider() *schema.Resource {
return &schema.Resource{
Schema: dataSourceCloudflareAccessIdentityProviderSchema(),
ReadContext: dataSourceCloudflareAccessIdentityProviderRead,
diff --git a/internal/sdkv2provider/data_source_access_identity_provider_test.go b/internal/sdkv2provider/data_source_access_identity_provider_test.go
index 259425612c..8d12619393 100644
--- a/internal/sdkv2provider/data_source_access_identity_provider_test.go
+++ b/internal/sdkv2provider/data_source_access_identity_provider_test.go
@@ -26,7 +26,7 @@ func TestAccCloudflareAccessIdentityProviderDataSource_PreventZoneIdAndAccountId
func testCloudflareAccessIdentityProviderDataSourceConfigConflictingFields(rnd string) string {
return fmt.Sprintf(`
-data "cloudflare_access_identity_provider" "%[1]s" {
+data "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "123abc"
zone_id = "abc123"
name = "foo"
@@ -50,7 +50,7 @@ func TestAccCloudflareAccessIdentityProviderDataSource_PreventNoInputSpecify(t *
func testCloudflareAccessIdentityProviderDataSourceNoInput(rnd string) string {
return fmt.Sprintf(`
-data "cloudflare_access_identity_provider" "%[1]s" {
+data "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
name = "foo"
}
`, rnd)
@@ -77,12 +77,12 @@ func TestAccCloudflareAccessIdentityProviderDataSourceNotFound(t *testing.T) {
func testAccCheckCloudflareAccessIdentityProviderDataSource_NotFound(accountID, name string) string {
return fmt.Sprintf(`
-data "cloudflare_access_identity_provider" "%[1]s" {
+data "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s-abc123"
}
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "github"
@@ -98,7 +98,7 @@ func TestAccCloudflareAccessIdentityProviderDataSource_GitHub(t *testing.T) {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := "data.cloudflare_access_identity_provider." + rnd
+ name := "data.cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -120,7 +120,7 @@ func TestAccCloudflareAccessIdentityProviderDataSource_GitHub(t *testing.T) {
func testAccCheckCloudflareAccessIdentityProviderDataSourceGitHub(accountID, name string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_identity_provider" "%[1]s" {
+ resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "github"
@@ -130,10 +130,10 @@ func testAccCheckCloudflareAccessIdentityProviderDataSourceGitHub(accountID, nam
}
}
- data "cloudflare_access_identity_provider" "%[1]s" {
+ data "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
- depends_on = [cloudflare_access_identity_provider.%[1]s]
+ depends_on = [cloudflare_zero_trust_access_identity_provider.%[1]s]
}
`, name, accountID)
}
diff --git a/internal/sdkv2provider/data_source_device_posture_rules_test.go b/internal/sdkv2provider/data_source_device_posture_rules_test.go
index 8bb0d878ea..3fabf71b04 100644
--- a/internal/sdkv2provider/data_source_device_posture_rules_test.go
+++ b/internal/sdkv2provider/data_source_device_posture_rules_test.go
@@ -13,7 +13,7 @@ import (
func TestAccCloudflareDevicePostureRules_DataSource(t *testing.T) {
rnd := generateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
- name := fmt.Sprintf("data.cloudflare_device_posture_rules.%s", rnd)
+ name := fmt.Sprintf("data.cloudflare_zero_trust_device_posture_rules.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@@ -37,7 +37,7 @@ func TestAccCloudflareDevicePostureRules_DataSource(t *testing.T) {
}
func testAccCloudflareDevicePostureRulesConfig(name, accountID string) string {
- return fmt.Sprintf(`resource "cloudflare_device_posture_rule" "%[1]s" {
+ return fmt.Sprintf(`resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "file"
@@ -53,11 +53,11 @@ func testAccCloudflareDevicePostureRulesConfig(name, accountID string) string {
}
}
-data "cloudflare_device_posture_rules" "%[1]s" {
+data "cloudflare_zero_trust_device_posture_rules" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
- depends_on = [cloudflare_device_posture_rule.%[1]s]
+ depends_on = [cloudflare_zero_trust_device_posture_rule.%[1]s]
}
`, name, accountID)
}
diff --git a/internal/sdkv2provider/data_source_record_test.go b/internal/sdkv2provider/data_source_record_test.go
index bb83ee92b6..cd53157888 100644
--- a/internal/sdkv2provider/data_source_record_test.go
+++ b/internal/sdkv2provider/data_source_record_test.go
@@ -97,7 +97,7 @@ resource "cloudflare_record" "%[1]s" {
zone_id = "%[2]s"
type = "A"
name = "%[1]s.%[3]s"
- value = "192.0.2.0"
+ content = "192.0.2.0"
}`, rnd, zoneID, domain)
}
@@ -112,7 +112,7 @@ resource "cloudflare_record" "%[1]s" {
zone_id = "%[2]s"
type = "TXT"
name = "%[1]s.%[3]s"
- value = "i am a text record"
+ content = "i am a text record"
}`, rnd, zoneID, domain)
}
@@ -128,14 +128,14 @@ resource "cloudflare_record" "%[1]s" {
zone_id = "%[2]s"
type = "MX"
name = "%[1]s.%[3]s"
- value = "mx1.example.com"
+ content = "mx1.example.com"
priority = 10
}
resource "cloudflare_record" "%[1]s_2" {
zone_id = "%[2]s"
type = "MX"
name = "%[1]s.%[3]s"
- value = "mx1.example.com"
+ content = "mx1.example.com"
priority = 20
}
`, rnd, zoneID, domain)
diff --git a/internal/sdkv2provider/data_source_tunnel.go b/internal/sdkv2provider/data_source_tunnel.go
index 3db87e632f..5df7dd03ef 100644
--- a/internal/sdkv2provider/data_source_tunnel.go
+++ b/internal/sdkv2provider/data_source_tunnel.go
@@ -12,6 +12,55 @@ import (
)
func dataSourceCloudflareTunnel() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: dataSourceCloudflareTunnelRead,
+ DeprecationMessage: "`cloudflare_tunnel` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_cloudflared` instead.",
+
+ Schema: map[string]*schema.Schema{
+ consts.AccountIDSchemaKey: {
+ Description: consts.AccountIDSchemaDescription,
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Name of the tunnel.",
+ ForceNew: true,
+ },
+ "is_deleted": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "If true, only include deleted tunnels. If false, exclude deleted tunnels. If empty, all tunnels will be included.",
+ ForceNew: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "ID of the tunnel.",
+ },
+ "status": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: fmt.Sprintf("The status of the tunnel. %s", renderAvailableDocumentationValuesStringSlice([]string{"inactive", "degraded", "healthy", "down"})),
+ },
+ "tunnel_type": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: fmt.Sprintf("The type of the tunnel. %s", renderAvailableDocumentationValuesStringSlice([]string{"cfd_tunnel", "warp_connector"})),
+ },
+ "remote_config": {
+ Type: schema.TypeBool,
+ Computed: true,
+ Description: "Whether the tunnel can be configured remotely from the Zero Trust dashboard.",
+ },
+ },
+ Description: "Use this datasource to lookup a tunnel in an account.",
+ }
+}
+
+func dataSourceCloudflareZeroTrustTunnelCloudflared() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceCloudflareTunnelRead,
diff --git a/internal/sdkv2provider/data_source_tunnel_test.go b/internal/sdkv2provider/data_source_tunnel_test.go
index 6e5b8cdf07..671d63fba6 100644
--- a/internal/sdkv2provider/data_source_tunnel_test.go
+++ b/internal/sdkv2provider/data_source_tunnel_test.go
@@ -19,7 +19,7 @@ func TestAccCloudflareTunnel_MatchName(t *testing.T) {
{
Config: testCloudflareTunnelMatchName(rnd),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "status", "inactive"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "status", "inactive"),
),
},
},
@@ -29,16 +29,16 @@ func TestAccCloudflareTunnel_MatchName(t *testing.T) {
func testCloudflareTunnelMatchName(name string) string {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
return fmt.Sprintf(`
-resource "cloudflare_tunnel" "%[2]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-data "cloudflare_tunnel" "%[2]s" {
- account_id = cloudflare_tunnel.%[2]s.account_id
- name = cloudflare_tunnel.%[2]s.name
- depends_on = [cloudflare_tunnel.%[2]s]
+data "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
+ account_id = cloudflare_zero_trust_tunnel_cloudflared.%[2]s.account_id
+ name = cloudflare_zero_trust_tunnel_cloudflared.%[2]s.name
+ depends_on = [cloudflare_zero_trust_tunnel_cloudflared.%[2]s]
}
`, accountID, name)
}
@@ -53,8 +53,8 @@ func TestAccCloudflareTunnel_MatchIsDeleted(t *testing.T) {
{
Config: testCloudflareTunnelMatchIsDeleted_Default(rnd),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "status", "inactive"),
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "is_deleted", "false"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "status", "inactive"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "is_deleted", "false"),
),
},
{
@@ -64,8 +64,8 @@ func TestAccCloudflareTunnel_MatchIsDeleted(t *testing.T) {
{
Config: testCloudflareTunnelMatchIsDeleted_DeletedTunnels(rnd),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "status", "inactive"),
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "is_deleted", "true"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "status", "inactive"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "is_deleted", "true"),
),
},
{
@@ -75,8 +75,8 @@ func TestAccCloudflareTunnel_MatchIsDeleted(t *testing.T) {
{
Config: testCloudflareTunnelMatchIsDeleted_ActiveTunnels(rnd),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "status", "inactive"),
- resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "is_deleted", "true"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "status", "inactive"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared."+rnd, "is_deleted", "true"),
),
ExpectError: regexp.MustCompile(`Error: No tunnels with name: ` + rnd),
},
@@ -87,17 +87,17 @@ func TestAccCloudflareTunnel_MatchIsDeleted(t *testing.T) {
func testCloudflareTunnelMatchIsDeleted_Default(name string) string {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
return fmt.Sprintf(`
-resource "cloudflare_tunnel" "%[2]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-data "cloudflare_tunnel" "%[2]s" {
+data "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
is_deleted = false
- depends_on = [cloudflare_tunnel.%[2]s]
+ depends_on = [cloudflare_zero_trust_tunnel_cloudflared.%[2]s]
}
`, accountID, name)
}
@@ -105,7 +105,7 @@ data "cloudflare_tunnel" "%[2]s" {
func testCloudflareTunnelMatchIsDeleted_DeletedTunnels(name string) string {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
return fmt.Sprintf(`
-data "cloudflare_tunnel" "%[2]s" {
+data "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
is_deleted = true
@@ -116,7 +116,7 @@ data "cloudflare_tunnel" "%[2]s" {
func testCloudflareTunnelMatchIsDeleted_ActiveTunnels(name string) string {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
return fmt.Sprintf(`
-data "cloudflare_tunnel" "%[2]s" {
+data "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
is_deleted = false
diff --git a/internal/sdkv2provider/data_source_tunnel_virtual_network.go b/internal/sdkv2provider/data_source_tunnel_virtual_network.go
index 0d61e17fc8..889f79135e 100644
--- a/internal/sdkv2provider/data_source_tunnel_virtual_network.go
+++ b/internal/sdkv2provider/data_source_tunnel_virtual_network.go
@@ -12,6 +12,37 @@ import (
)
func dataSourceCloudflareTunnelVirtualNetwork() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: dataSourceCloudflareTunnelVirtualNetworkRead,
+
+ Schema: map[string]*schema.Schema{
+ consts.AccountIDSchemaKey: {
+ Description: consts.AccountIDSchemaDescription,
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "name": {
+ Description: "The Virtual Network Name.",
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "comment": {
+ Description: "The Virtual Network Comment.",
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "is_default": {
+ Description: "If true, only include deleted virtual networks. If false, exclude deleted virtual networks. If empty, all virtual networks will be included.",
+ Type: schema.TypeBool,
+ Computed: true,
+ },
+ },
+ Description: "Use this datasource to lookup a tunnel virtual network in an account.",
+ DeprecationMessage: "`cloudflare_tunnel_virtual_network` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_virtual_network` instead.",
+ }
+}
+
+func dataSourceCloudflareZeroTrustTunnelVirtualNetwork() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceCloudflareTunnelVirtualNetworkRead,
diff --git a/internal/sdkv2provider/data_source_tunnel_virtual_network_test.go b/internal/sdkv2provider/data_source_tunnel_virtual_network_test.go
index 0e90a25da1..7a67ba9273 100644
--- a/internal/sdkv2provider/data_source_tunnel_virtual_network_test.go
+++ b/internal/sdkv2provider/data_source_tunnel_virtual_network_test.go
@@ -18,7 +18,7 @@ func TestAccCloudflareTunneVirtualNetwork_MatchName(t *testing.T) {
{
Config: testCloudflareTunnelVirtualNetworkMatchName(rnd),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr("data.cloudflare_tunnel_virtual_network."+rnd, "comment", "test"),
+ resource.TestCheckResourceAttr("data.cloudflare_zero_trust_tunnel_cloudflared_virtual_network."+rnd, "comment", "test"),
),
},
},
@@ -28,15 +28,15 @@ func TestAccCloudflareTunneVirtualNetwork_MatchName(t *testing.T) {
func testCloudflareTunnelVirtualNetworkMatchName(name string) string {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
return fmt.Sprintf(`
-resource "cloudflare_tunnel_virtual_network" "%[2]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_virtual_network" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
comment = "test"
}
-data "cloudflare_tunnel_virtual_network" "%[2]s" {
- account_id = cloudflare_tunnel_virtual_network.%[2]s.account_id
- name = cloudflare_tunnel_virtual_network.%[2]s.name
- depends_on = ["cloudflare_tunnel_virtual_network.%[2]s"]
+data "cloudflare_zero_trust_tunnel_cloudflared_virtual_network" "%[2]s" {
+ account_id = cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%[2]s.account_id
+ name = cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%[2]s.name
+ depends_on = ["cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%[2]s"]
}
`, accountID, name)
}
diff --git a/internal/sdkv2provider/import_cloudflare_worker_script_test.go b/internal/sdkv2provider/import_cloudflare_worker_script_test.go
index bcc9783d58..86123448ec 100644
--- a/internal/sdkv2provider/import_cloudflare_worker_script_test.go
+++ b/internal/sdkv2provider/import_cloudflare_worker_script_test.go
@@ -19,7 +19,7 @@ func TestAccCloudflareWorkerScript_Import(t *testing.T) {
var script cloudflare.WorkerScript
rnd := generateRandomResourceName()
- name := "cloudflare_worker_script." + rnd
+ name := "cloudflare_workers_script." + rnd
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
diff --git a/internal/sdkv2provider/import_resource_cloudflare_record_test.go b/internal/sdkv2provider/import_resource_cloudflare_record_test.go
index fcfb1400ce..a5a5096217 100644
--- a/internal/sdkv2provider/import_resource_cloudflare_record_test.go
+++ b/internal/sdkv2provider/import_resource_cloudflare_record_test.go
@@ -24,7 +24,7 @@ func TestAccCloudflareRecord_ImportBasic(t *testing.T) {
ImportStateIdPrefix: fmt.Sprintf("%s/", zoneID),
ImportState: true,
ImportStateVerify: true,
- ImportStateVerifyIgnore: []string{"allow_overwrite"},
+ ImportStateVerifyIgnore: []string{"allow_overwrite", "content"},
},
},
})
@@ -48,7 +48,7 @@ func TestAccCloudflareRecord_ImportSRV(t *testing.T) {
ImportStateIdPrefix: fmt.Sprintf("%s/", zoneID),
ImportState: true,
ImportStateVerify: true,
- ImportStateVerifyIgnore: []string{"allow_overwrite"},
+ ImportStateVerifyIgnore: []string{"allow_overwrite", "content"},
},
},
})
diff --git a/internal/sdkv2provider/provider.go b/internal/sdkv2provider/provider.go
index acc01e47a5..dbd2bc13d7 100644
--- a/internal/sdkv2provider/provider.go
+++ b/internal/sdkv2provider/provider.go
@@ -21,8 +21,8 @@ import (
const (
MAXIMUM_NUMBER_OF_ENTITIES_REACHED_SUMMARY = "You've attempted to add a new %[1]s to the `terraform-plugin-sdkv2` which is no longer considered suitable for use."
MAXIMUM_NUMBER_OF_ENTITIES_REACHED_DETAIL = "Due the number of known internal issues with `terraform-plugin-sdkv2` (most notably handling of zero values), we are no longer recommending using it and instead, advise using `terraform-plugin-framework` exclusively. If you must use terraform-plugin-sdkv2 for this new %[1]s you should first discuss it with a maintainer to fully understand the impact and potential ramifications. Only then should you bump %[2]s to include your %[1]s."
- MAXIMUM_ALLOWED_SDKV2_RESOURCES = 108
- MAXIMUM_ALLOWED_SDKV2_DATASOURCES = 19
+ MAXIMUM_ALLOWED_SDKV2_RESOURCES = 145
+ MAXIMUM_ALLOWED_SDKV2_DATASOURCES = 23
)
func init() {
@@ -166,40 +166,55 @@ func New(version string) func() *schema.Provider {
},
DataSourcesMap: map[string]*schema.Resource{
- "cloudflare_access_application": dataSourceCloudflareAccessApplication(),
- "cloudflare_access_identity_provider": dataSourceCloudflareAccessIdentityProvider(),
- "cloudflare_account_roles": dataSourceCloudflareAccountRoles(),
- "cloudflare_accounts": dataSourceCloudflareAccounts(),
- "cloudflare_devices": dataSourceCloudflareDevices(),
- "cloudflare_device_posture_rules": dataSourceCloudflareDevicePostureRules(),
- "cloudflare_ip_ranges": dataSourceCloudflareIPRanges(),
- "cloudflare_list": dataSourceCloudflareList(),
- "cloudflare_lists": dataSourceCloudflareLists(),
- "cloudflare_tunnel_virtual_network": dataSourceCloudflareTunnelVirtualNetwork(),
- "cloudflare_load_balancer_pools": dataSourceCloudflareLoadBalancerPools(),
- "cloudflare_origin_ca_root_certificate": dataSourceCloudflareOriginCARootCertificate(),
- "cloudflare_record": dataSourceCloudflareRecord(),
- "cloudflare_rulesets": dataSourceCloudflareRulesets(),
- "cloudflare_zone_cache_reserve": dataSourceCloudflareZoneCacheReserve(),
- "cloudflare_tunnel": dataSourceCloudflareTunnel(),
- "cloudflare_zone_dnssec": dataSourceCloudflareZoneDNSSEC(),
- "cloudflare_zone": dataSourceCloudflareZone(),
- "cloudflare_zones": dataSourceCloudflareZones(),
+ "cloudflare_access_application": dataSourceCloudflareAccessApplication(),
+ "cloudflare_zero_trust_access_application": dataSourceCloudflareZeroTrustAccessApplication(),
+ "cloudflare_access_identity_provider": dataSourceCloudflareAccessIdentityProvider(),
+ "cloudflare_zero_trust_access_identity_provider": dataSourceCloudflareZeroTrustAccessIdentityProvider(),
+ "cloudflare_account_roles": dataSourceCloudflareAccountRoles(),
+ "cloudflare_accounts": dataSourceCloudflareAccounts(),
+ "cloudflare_devices": dataSourceCloudflareDevices(),
+ "cloudflare_device_posture_rules": dataSourceCloudflareDevicePostureRules(),
+ "cloudflare_ip_ranges": dataSourceCloudflareIPRanges(),
+ "cloudflare_list": dataSourceCloudflareList(),
+ "cloudflare_lists": dataSourceCloudflareLists(),
+ "cloudflare_tunnel_virtual_network": dataSourceCloudflareTunnelVirtualNetwork(),
+ "cloudflare_zero_trust_tunnel_virtual_network": dataSourceCloudflareZeroTrustTunnelVirtualNetwork(),
+ "cloudflare_load_balancer_pools": dataSourceCloudflareLoadBalancerPools(),
+ "cloudflare_origin_ca_root_certificate": dataSourceCloudflareOriginCARootCertificate(),
+ "cloudflare_record": dataSourceCloudflareRecord(),
+ "cloudflare_rulesets": dataSourceCloudflareRulesets(),
+ "cloudflare_zone_cache_reserve": dataSourceCloudflareZoneCacheReserve(),
+ "cloudflare_tunnel": dataSourceCloudflareTunnel(),
+ "cloudflare_zero_trust_tunnel_cloudflared": dataSourceCloudflareZeroTrustTunnelCloudflared(),
+ "cloudflare_zone_dnssec": dataSourceCloudflareZoneDNSSEC(),
+ "cloudflare_zone": dataSourceCloudflareZone(),
+ "cloudflare_zones": dataSourceCloudflareZones(),
},
ResourcesMap: map[string]*schema.Resource{
"cloudflare_access_application": resourceCloudflareAccessApplication(),
+ "cloudflare_zero_trust_access_application": resourceCloudflareZeroTrustAccessApplication(),
"cloudflare_access_ca_certificate": resourceCloudflareAccessCACertificate(),
+ "cloudflare_zero_trust_access_short_lived_certificate": resourceCloudflareZeroTrustAccessCACertificate(),
"cloudflare_access_group": resourceCloudflareAccessGroup(),
+ "cloudflare_zero_trust_access_group": resourceCloudflareZeroTrustAccessGroup(),
"cloudflare_access_identity_provider": resourceCloudflareAccessIdentityProvider(),
+ "cloudflare_zero_trust_access_identity_provider": resourceCloudflareZeroTrustAccessIdentityProvider(),
"cloudflare_access_custom_page": resourceCloudflareAccessCustomPage(),
+ "cloudflare_zero_trust_access_custom_page": resourceCloudflareZeroTrustAccessCustomPage(),
"cloudflare_access_keys_configuration": resourceCloudflareAccessKeysConfiguration(),
+ "cloudflare_zero_trust_key_access_key_configuration": resourceCloudflareZeroTrustAccessKeyConfiguration(),
"cloudflare_access_mutual_tls_certificate": resourceCloudflareAccessMutualTLSCertificate(),
+ "cloudflare_zero_trust_access_mtls_certificate": resourceCloudflareZeroTrustAccessMutualTLSCertificate(),
"cloudflare_access_organization": resourceCloudflareAccessOrganization(),
+ "cloudflare_zero_trust_access_organization": resourceCloudflareZeroTrustAccessOrganization(),
"cloudflare_access_policy": resourceCloudflareAccessPolicy(),
+ "cloudflare_zero_trust_access_policy": resourceCloudflareZeroTrustAccessPolicy(),
"cloudflare_access_rule": resourceCloudflareAccessRule(),
"cloudflare_access_service_token": resourceCloudflareAccessServiceToken(),
+ "cloudflare_zero_trust_access_service_token": resourceCloudflareZeroTrustAccessServiceToken(),
"cloudflare_access_tag": resourceCloudflareAccessTag(),
+ "cloudflare_zero_trust_access_tag": resourceCloudflareZeroTrustAccessTag(),
"cloudflare_account_member": resourceCloudflareAccountMember(),
"cloudflare_account": resourceCloudflareAccount(),
"cloudflare_address_map": resourceCloudflareAddressMap(),
@@ -219,22 +234,32 @@ func New(version string) func() *schema.Provider {
"cloudflare_custom_pages": resourceCloudflareCustomPages(),
"cloudflare_custom_ssl": resourceCloudflareCustomSsl(),
"cloudflare_device_dex_test": resourceCloudflareDeviceDexTest(),
+ "cloudflare_zero_trust_dex_test": resourceCloudflareZeroTrustDexTest(),
"cloudflare_device_managed_networks": resourceCloudflareDeviceManagedNetworks(),
+ "cloudflare_zero_trust_device_managed_networks": resourceCloudflareZeroTrustDeviceManagedNetworks(),
"cloudflare_device_policy_certificates": resourceCloudflareDevicePolicyCertificates(),
+ "cloudflare_zero_trust_device_certificates": resourceCloudflareZeroTrustDevicePolicyCertificates(),
"cloudflare_device_posture_integration": resourceCloudflareDevicePostureIntegration(),
+ "cloudflare_zero_trust_device_posture_integration": resourceCloudflareZeroTrustDevicePostureIntegration(),
"cloudflare_device_posture_rule": resourceCloudflareDevicePostureRule(),
+ "cloudflare_zero_trust_device_posture_rule": resourceCloudflareZeroTrustDevicePostureRule(),
"cloudflare_device_settings_policy": resourceCloudflareDeviceSettingsPolicy(),
+ "cloudflare_zero_trust_device_profiles": resourceCloudflareZeroTrustDeviceProfiles(),
"cloudflare_dlp_profile": resourceCloudflareDLPProfile(),
+ "cloudflare_zero_trust_dlp_profile": resourceCloudflareZeroTrustDLPProfile(),
"cloudflare_email_routing_catch_all": resourceCloudflareEmailRoutingCatchAll(),
"cloudflare_email_routing_settings": resourceCloudflareEmailRoutingSettings(),
"cloudflare_fallback_domain": resourceCloudflareFallbackDomain(),
+ "cloudflare_zero_trust_local_fallback_domain": resourceCloudflareZeroTrustLocalFallbackDomain(),
"cloudflare_filter": resourceCloudflareFilter(),
"cloudflare_firewall_rule": resourceCloudflareFirewallRule(),
"cloudflare_gre_tunnel": resourceCloudflareGRETunnel(),
+ "cloudflare_magic_wan_gre_tunnel": resourceCloudflareMagicWANGRETunnel(),
"cloudflare_healthcheck": resourceCloudflareHealthcheck(),
"cloudflare_hostname_tls_setting": resourceCloudflareHostnameTLSSetting(),
"cloudflare_hostname_tls_setting_ciphers": resourceCloudflareHostnameTLSSettingCiphers(),
"cloudflare_ipsec_tunnel": resourceCloudflareIPsecTunnel(),
+ "cloudflare_magic_wan_ipsec_tunnel": resourceCloudflareMagicWANIPsecTunnel(),
"cloudflare_keyless_certificate": resourceCloudflareKeylessCertificate(),
"cloudflare_list": resourceCloudflareList(),
"cloudflare_load_balancer_monitor": resourceCloudflareLoadBalancerMonitor(),
@@ -260,19 +285,30 @@ func New(version string) func() *schema.Provider {
"cloudflare_regional_tiered_cache": resourceCloudflareRegionalTieredCache(),
"cloudflare_spectrum_application": resourceCloudflareSpectrumApplication(),
"cloudflare_split_tunnel": resourceCloudflareSplitTunnel(),
+ "cloudflare_zero_trust_split_tunnel": resourceCloudflareZeroTrustSplitTunnel(),
"cloudflare_static_route": resourceCloudflareStaticRoute(),
+ "cloudflare_magic_wan_static_route": resourceCloudflareMagicWANStaticRoute(),
"cloudflare_bot_management": resourceCloudflareBotManagement(),
"cloudflare_teams_account": resourceCloudflareTeamsAccount(),
+ "cloudflare_zero_trust_gateway_settings": resourceCloudflareZeroTrustGatewaySettings(),
"cloudflare_teams_list": resourceCloudflareTeamsList(),
+ "cloudflare_zero_trust_list": resourceCloudflareZeroTrustList(),
"cloudflare_teams_location": resourceCloudflareTeamsLocation(),
+ "cloudflare_zero_trust_dns_location": resourceCloudflareZeroTrustDNSLocation(),
"cloudflare_teams_proxy_endpoint": resourceCloudflareTeamsProxyEndpoint(),
+ "cloudflare_zero_trust_gateway_proxy_endpoint": resourceCloudflareZeroTrustGatewayProxyEndpoint(),
"cloudflare_teams_rule": resourceCloudflareTeamsRule(),
+ "cloudflare_zero_trust_gateway_policy": resourceCloudflareZeroTrustGatewayPolicy(),
"cloudflare_tiered_cache": resourceCloudflareTieredCache(),
"cloudflare_total_tls": resourceCloudflareTotalTLS(),
"cloudflare_tunnel_config": resourceCloudflareTunnelConfig(),
+ "cloudflare_zero_trust_tunnel_cloudflared_config": resourceCloudflareZeroTrustTunnelCloudflaredConfig(),
"cloudflare_tunnel_route": resourceCloudflareTunnelRoute(),
+ "cloudflare_zero_trust_tunnel_route": resourceCloudflareZeroTrustTunnelRoute(),
"cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(),
+ "cloudflare_zero_trust_tunnel_virtual_network": resourceCloudflareZeroTrustTunnelVirtualNetwork(),
"cloudflare_tunnel": resourceCloudflareTunnel(),
+ "cloudflare_zero_trust_tunnel_cloudflared": resourceCloudflareZeroTrustTunnelCloudflared(),
"cloudflare_url_normalization_settings": resourceCloudflareURLNormalizationSettings(),
"cloudflare_user_agent_blocking_rule": resourceCloudflareUserAgentBlockingRules(),
"cloudflare_waiting_room_event": resourceCloudflareWaitingRoomEvent(),
@@ -287,6 +323,11 @@ func New(version string) func() *schema.Provider {
"cloudflare_worker_route": resourceCloudflareWorkerRoute(),
"cloudflare_worker_script": resourceCloudflareWorkerScript(),
"cloudflare_worker_secret": resourceCloudflareWorkerSecret(),
+ "cloudflare_workers_cron_trigger": resourceCloudflareWorkersCronTrigger(),
+ "cloudflare_workers_domain": resourceCloudflareWorkersDomain(),
+ "cloudflare_workers_route": resourceCloudflareWorkersRoute(),
+ "cloudflare_workers_script": resourceCloudflareWorkersScript(),
+ "cloudflare_workers_secret": resourceCloudflareWorkersSecret(),
"cloudflare_workers_kv_namespace": resourceCloudflareWorkersKVNamespace(),
"cloudflare_workers_kv": resourceCloudflareWorkerKV(),
"cloudflare_zone_cache_reserve": resourceCloudflareZoneCacheReserve(),
diff --git a/internal/sdkv2provider/resource_cloudflare_access_application.go b/internal/sdkv2provider/resource_cloudflare_access_application.go
index a9d3bdfe59..c607e47816 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_application.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_application.go
@@ -15,6 +15,25 @@ import (
)
func resourceCloudflareAccessApplication() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessApplicationSchema(),
+ CreateContext: resourceCloudflareAccessApplicationCreate,
+ ReadContext: resourceCloudflareAccessApplicationRead,
+ UpdateContext: resourceCloudflareAccessApplicationUpdate,
+ DeleteContext: resourceCloudflareAccessApplicationDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessApplicationImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Access Application resource. Access
+ Applications are used to restrict access to a whole application using an
+ authorisation gateway managed by Cloudflare.
+ `),
+ DeprecationMessage: "`cloudflare_access_application` is now deprecated and will be removed in the next major version. Use `zero_trust_access_application` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessApplication() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessApplicationSchema(),
CreateContext: resourceCloudflareAccessApplicationCreate,
@@ -94,9 +113,10 @@ func resourceCloudflareAccessApplicationCreate(ctx context.Context, d *schema.Re
if appType == "app_launcher" {
newAccessApplication.AccessAppLauncherCustomization = cloudflare.AccessAppLauncherCustomization{
- LogoURL: d.Get("app_launcher_logo_url").(string),
- BackgroundColor: d.Get("bg_color").(string),
- HeaderBackgroundColor: d.Get("header_bg_color").(string),
+ LogoURL: d.Get("app_launcher_logo_url").(string),
+ BackgroundColor: d.Get("bg_color").(string),
+ HeaderBackgroundColor: d.Get("header_bg_color").(string),
+ SkipAppLauncherLoginPage: cloudflare.BoolPtr(d.Get("skip_app_launcher_login_page").(bool)),
}
if _, ok := d.GetOk("landing_page_design"); ok {
@@ -171,7 +191,13 @@ func resourceCloudflareAccessApplicationRead(ctx context.Context, d *schema.Reso
d.Set("name", accessApplication.Name)
d.Set("aud", accessApplication.AUD)
d.Set("session_duration", accessApplication.SessionDuration)
- d.Set("domain", accessApplication.Domain)
+ if _, domainWasSet := d.GetOk("domain"); domainWasSet {
+ // Only set the domain if it was set in the configuration, as apps can be created without a domain
+ // if they define a non-empty self_hosted_domains array
+ d.Set("domain", accessApplication.Domain)
+ } else {
+ d.Set("domain", nil)
+ }
d.Set("type", accessApplication.Type)
d.Set("auto_redirect_to_identity", accessApplication.AutoRedirectToIdentity)
d.Set("enable_binding_cookie", accessApplication.EnableBindingCookie)
@@ -190,6 +216,7 @@ func resourceCloudflareAccessApplicationRead(ctx context.Context, d *schema.Reso
d.Set("bg_color", accessApplication.AccessAppLauncherCustomization.BackgroundColor)
d.Set("header_bg_color", accessApplication.AccessAppLauncherCustomization.HeaderBackgroundColor)
d.Set("app_launcher_logo_url", accessApplication.AccessAppLauncherCustomization.LogoURL)
+ d.Set("skip_app_launcher_login_page", accessApplication.AccessAppLauncherCustomization.SkipAppLauncherLoginPage)
d.Set("allow_authenticate_via_warp", accessApplication.AllowAuthenticateViaWarp)
d.Set("options_preflight_bypass", accessApplication.OptionsPreflightBypass)
@@ -283,8 +310,8 @@ func resourceCloudflareAccessApplicationUpdate(ctx context.Context, d *schema.Re
updatedAccessApplication.SelfHostedDomains = expandInterfaceToStringList(value.(*schema.Set).List())
}
- if value, ok := d.GetOk("policies"); ok {
- policies := expandInterfaceToStringList(value)
+ if d.HasChange("policies") {
+ policies := expandInterfaceToStringList(d.Get("policies"))
updatedAccessApplication.Policies = &policies
}
diff --git a/internal/sdkv2provider/resource_cloudflare_access_application_test.go b/internal/sdkv2provider/resource_cloudflare_access_application_test.go
index 1fac6ba551..9af3d79834 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_application_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_application_test.go
@@ -17,8 +17,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_access_application", &resource.Sweeper{
- Name: "cloudflare_access_application",
+ resource.AddTestSweepers("cloudflare_zero_trust_access_application", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_application",
F: testSweepCloudflareAccessApplications,
})
}
@@ -77,7 +77,7 @@ var (
func TestAccCloudflareAccessApplication_BasicZone(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -107,7 +107,7 @@ func TestAccCloudflareAccessApplication_BasicZone(t *testing.T) {
func TestAccCloudflareAccessApplication_BasicAccount(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -138,8 +138,8 @@ func TestAccCloudflareAccessApplication_BasicAccount(t *testing.T) {
func TestAccCloudflareAccessApplication_WithSCIMConfigHttpBasic(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
- idpName := fmt.Sprintf("cloudflare_access_identity_provider.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
+ idpName := fmt.Sprintf("cloudflare_zero_trust_access_identity_provider.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -179,8 +179,8 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigHttpBasic(t *testing.T) {
func TestAccCloudflareAccessApplication_UpdateSCIMConfig(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
- idpName := fmt.Sprintf("cloudflare_access_identity_provider.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
+ idpName := fmt.Sprintf("cloudflare_zero_trust_access_identity_provider.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -274,8 +274,8 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigHttpBasicMissingRequired(t
func TestAccCloudflareAccessApplication_WithSCIMConfigOAuthBearerToken(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
- idpName := fmt.Sprintf("cloudflare_access_identity_provider.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
+ idpName := fmt.Sprintf("cloudflare_zero_trust_access_identity_provider.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -314,8 +314,8 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigOAuthBearerToken(t *testin
func TestAccCloudflareAccessApplication_WithSCIMConfigOAuth2(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
- idpName := fmt.Sprintf("cloudflare_access_identity_provider.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
+ idpName := fmt.Sprintf("cloudflare_zero_trust_access_identity_provider.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -395,7 +395,7 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigAuthenticationInvalid(t *t
func TestAccCloudflareAccessApplication_WithCORS(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -425,7 +425,7 @@ func TestAccCloudflareAccessApplication_WithCORS(t *testing.T) {
func TestAccCloudflareAccessApplication_WithSAMLSaas(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -472,7 +472,7 @@ func TestAccCloudflareAccessApplication_WithSAMLSaas_Import(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := "cloudflare_access_application." + rnd
+ name := "cloudflare_zero_trust_access_application." + rnd
checkFn := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
@@ -521,7 +521,7 @@ func TestAccCloudflareAccessApplication_WithSAMLSaas_Import(t *testing.T) {
func TestAccCloudflareAccessApplication_WithOIDCSaas(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -552,6 +552,7 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.3", "profile"),
resource.TestCheckResourceAttr(name, "saas_app.0.app_launcher_url", "https://saas-app.example/sso/login"),
resource.TestCheckResourceAttr(name, "saas_app.0.group_filter_regex", ".*"),
+ resource.TestCheckResourceAttr(name, "saas_app.0.access_token_lifetime", "5m"),
resource.TestCheckResourceAttr(name, "saas_app.0.allow_pkce_without_client_secret", "false"),
resource.TestCheckResourceAttr(name, "saas_app.0.refresh_token_options.0.lifetime", "1h"),
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.#", "1"),
@@ -574,7 +575,7 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := "cloudflare_access_application." + rnd
+ name := "cloudflare_zero_trust_access_application." + rnd
checkFn := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
@@ -595,6 +596,7 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.3", "profile"),
resource.TestCheckResourceAttr(name, "saas_app.0.app_launcher_url", "https://saas-app.example/sso/login"),
resource.TestCheckResourceAttr(name, "saas_app.0.group_filter_regex", ".*"),
+ resource.TestCheckResourceAttr(name, "saas_app.0.access_token_lifetime", "5m"),
resource.TestCheckResourceAttr(name, "saas_app.0.allow_pkce_without_client_secret", "false"),
resource.TestCheckResourceAttr(name, "saas_app.0.refresh_token_options.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.refresh_token_options.0.lifetime", "1h"),
@@ -633,7 +635,7 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) {
func TestAccCloudflareAccessApplication_WithAutoRedirectToIdentity(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -660,7 +662,7 @@ func TestAccCloudflareAccessApplication_WithAutoRedirectToIdentity(t *testing.T)
func TestAccCloudflareAccessApplication_WithEnableBindingCookie(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -686,7 +688,7 @@ func TestAccCloudflareAccessApplication_WithEnableBindingCookie(t *testing.T) {
func TestAccCloudflareAccessApplication_WithCustomDenyFields(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -714,7 +716,7 @@ func TestAccCloudflareAccessApplication_WithCustomDenyFields(t *testing.T) {
func TestAccCloudflareAccessApplication_WithADefinedIdps(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -763,7 +765,7 @@ func TestAccCloudflareAccessApplication_WithMultipleIdpsReordered(t *testing.T)
func TestAccCloudflareAccessApplication_WithHttpOnlyCookieAttribute(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -789,7 +791,7 @@ func TestAccCloudflareAccessApplication_WithHttpOnlyCookieAttribute(t *testing.T
func TestAccCloudflareAccessApplication_WithHTTPOnlyCookieAttributeSetToFalse(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -815,7 +817,7 @@ func TestAccCloudflareAccessApplication_WithHTTPOnlyCookieAttributeSetToFalse(t
func TestAccCloudflareAccessApplication_WithSameSiteCookieAttribute(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -841,7 +843,7 @@ func TestAccCloudflareAccessApplication_WithSameSiteCookieAttribute(t *testing.T
func TestAccCloudflareAccessApplication_WithLogoURL(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -867,7 +869,7 @@ func TestAccCloudflareAccessApplication_WithLogoURL(t *testing.T) {
func TestAccCloudflareAccessApplication_WithSkipInterstitial(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -893,7 +895,7 @@ func TestAccCloudflareAccessApplication_WithSkipInterstitial(t *testing.T) {
func TestAccCloudflareAccessApplication_WithAppLauncherVisible(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -919,7 +921,7 @@ func TestAccCloudflareAccessApplication_WithAppLauncherVisible(t *testing.T) {
func TestAccCloudflareAccessApplication_WithSelfHostedDomains(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -934,8 +936,25 @@ func TestAccCloudflareAccessApplication_WithSelfHostedDomains(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
resource.TestCheckResourceAttr(name, "name", rnd),
- resource.TestCheckResourceAttrSet(name, "domain"),
resource.TestCheckResourceAttr(name, "self_hosted_domains.#", "2"),
+ resource.TestCheckResourceAttr(name, "self_hosted_domains.0", fmt.Sprintf("d1.%s.%s", rnd, domain)),
+ resource.TestCheckResourceAttr(name, "self_hosted_domains.1", fmt.Sprintf("d2.%s.%s", rnd, domain)),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "type", "self_hosted"),
+ resource.TestCheckResourceAttr(name, "session_duration", "24h"),
+ resource.TestCheckResourceAttr(name, "cors_headers.#", "0"),
+ resource.TestCheckResourceAttr(name, "sass_app.#", "0"),
+ resource.TestCheckResourceAttr(name, "auto_redirect_to_identity", "false"),
+ ),
+ },
+ {
+ Config: testAccCloudflareAccessApplicationWithSelfHostedDomains2(rnd, domain, cloudflare.AccountIdentifier(accountID)),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "self_hosted_domains.#", "2"),
+ resource.TestCheckResourceAttr(name, "self_hosted_domains.0", fmt.Sprintf("d3.%s.%s", rnd, domain)),
+ resource.TestCheckResourceAttr(name, "self_hosted_domains.1", fmt.Sprintf("d4.%s.%s", rnd, domain)),
resource.TestCheckResourceAttr(name, "type", "self_hosted"),
resource.TestCheckResourceAttr(name, "session_duration", "24h"),
resource.TestCheckResourceAttr(name, "cors_headers.#", "0"),
@@ -949,7 +968,7 @@ func TestAccCloudflareAccessApplication_WithSelfHostedDomains(t *testing.T) {
func TestAccCloudflareAccessApplication_WithDefinedTags(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -976,7 +995,7 @@ func TestAccCloudflareAccessApplication_WithDefinedTags(t *testing.T) {
func TestAccCloudflareAccessApplication_WithReusablePolicies(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -1001,7 +1020,7 @@ func TestAccCloudflareAccessApplication_WithReusablePolicies(t *testing.T) {
func TestAccCloudflareAccessApplication_WithAppLauncherCustomization(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -1029,6 +1048,7 @@ func TestAccCloudflareAccessApplication_WithAppLauncherCustomization(t *testing.
resource.TestCheckResourceAttr(name, "footer_links.#", "1"),
resource.TestCheckResourceAttr(name, "footer_links.0.name", "footer link"),
resource.TestCheckResourceAttr(name, "footer_links.0.url", "https://www.cloudflare.com"),
+ resource.TestCheckResourceAttr(name, "skip_app_launcher_login_page", "false"),
),
},
},
@@ -1037,7 +1057,7 @@ func TestAccCloudflareAccessApplication_WithAppLauncherCustomization(t *testing.
func TestAccCloudflareAccessApplication_AuthTypeForcesNewResource(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_application.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -1065,7 +1085,7 @@ func TestAccCloudflareAccessApplication_AuthTypeForcesNewResource(t *testing.T)
func testAccCloudflareAccessApplicationConfigBasic(rnd string, domain string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[1]s"
domain = "%[1]s.%[2]s"
@@ -1078,7 +1098,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithCORS(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1097,7 +1117,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithSAMLSaas(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "saas"
@@ -1133,7 +1153,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithOIDCSaas(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "saas"
@@ -1145,6 +1165,7 @@ resource "cloudflare_access_application" "%[1]s" {
scopes = ["openid", "email", "profile", "groups"]
app_launcher_url = "https://saas-app.example/sso/login"
group_filter_regex = ".*"
+ access_token_lifetime = "5m"
allow_pkce_without_client_secret = false
refresh_token_options {
lifetime = "1h"
@@ -1170,29 +1191,29 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithAutoRedirectToIdentity(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
type = "onetimepin"
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
type = "self_hosted"
session_duration = "24h"
auto_redirect_to_identity = true
- allowed_idps = [cloudflare_access_identity_provider.%[1]s.id]
+ allowed_idps = [cloudflare_zero_trust_access_identity_provider.%[1]s.id]
- depends_on = ["cloudflare_access_identity_provider.%[1]s"]
+ depends_on = ["cloudflare_zero_trust_access_identity_provider.%[1]s"]
}
`, rnd, zoneID, domain)
}
func testAccCloudflareAccessApplicationConfigWithEnableBindingCookie(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1205,7 +1226,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithCustomDenyFields(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1220,32 +1241,32 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithADefinedIdp(rnd, zoneID, domain string, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[4]s"
name = "%[1]s"
type = "onetimepin"
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
type = "self_hosted"
session_duration = "24h"
auto_redirect_to_identity = true
- allowed_idps = [cloudflare_access_identity_provider.%[1]s.id]
+ allowed_idps = [cloudflare_zero_trust_access_identity_provider.%[1]s.id]
}
`, rnd, zoneID, domain, accountID)
}
func testAccCloudflareAccessApplicationConfigWithMultipleIdps(rnd, zoneID, domain, accountID, idp1, idp2 string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[5]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[5]s" {
account_id = "%[4]s"
name = "%[5]s"
type = "onetimepin"
}
-resource "cloudflare_access_identity_provider" "%[6]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[6]s" {
account_id = "%[4]s"
name = "%[6]s"
type = "github"
@@ -1255,15 +1276,15 @@ resource "cloudflare_access_identity_provider" "%[6]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
type = "self_hosted"
session_duration = "24h"
allowed_idps = [
- cloudflare_access_identity_provider.%[5]s.id,
- cloudflare_access_identity_provider.%[6]s.id,
+ cloudflare_zero_trust_access_identity_provider.%[5]s.id,
+ cloudflare_zero_trust_access_identity_provider.%[6]s.id,
]
}
`, rnd, zoneID, domain, accountID, idp1, idp2)
@@ -1271,7 +1292,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithHTTPOnlyCookieAttribute(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1284,7 +1305,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithHTTPOnlyCookieAttributeSetToFalse(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1297,7 +1318,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigSameSiteCookieAttribute(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1310,7 +1331,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigSkipInterstitial(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1323,7 +1344,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigWithAppLauncherVisible(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1336,7 +1357,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationConfigLogoURL(rnd, zoneID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
@@ -1349,7 +1370,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccessApplicationWithAppLauncherCustomizationFields(rnd, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
type = "app_launcher"
session_duration = "24h"
@@ -1377,7 +1398,7 @@ func testAccessApplicationWithAppLauncherCustomizationFields(rnd, accountID stri
func testAccCloudflareAccessApplicationWithSelfHostedDomains(rnd string, domain string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[1]s"
type = "self_hosted"
@@ -1391,11 +1412,27 @@ resource "cloudflare_access_application" "%[1]s" {
`, rnd, domain, identifier.Type, identifier.Identifier)
}
+func testAccCloudflareAccessApplicationWithSelfHostedDomains2(rnd string, domain string, identifier *cloudflare.ResourceContainer) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
+ %[3]s_id = "%[4]s"
+ name = "%[1]s"
+ type = "self_hosted"
+ session_duration = "24h"
+ auto_redirect_to_identity = false
+ self_hosted_domains = [
+ "d3.%[1]s.%[2]s",
+ "d4.%[1]s.%[2]s"
+ ]
+}
+`, rnd, domain, identifier.Type, identifier.Identifier)
+}
+
func testAccCheckCloudflareAccessApplicationDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_application" {
+ if rs.Type != "cloudflare_zero_trust_access_application" {
continue
}
@@ -1421,7 +1458,7 @@ func testAccCheckCloudflareAccessApplicationDestroy(s *terraform.State) error {
func TestAccCloudflareAccessApplicationWithZoneID(t *testing.T) {
rnd := generateRandomResourceName()
- name := "cloudflare_access_application." + rnd
+ name := "cloudflare_zero_trust_access_application." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
updatedName := fmt.Sprintf("%s-updated", rnd)
@@ -1553,7 +1590,7 @@ func TestAccCloudflareAccessApplicationMisconfiguredCORSCredentialsAllowingWildc
func testAccessApplicationWithZoneID(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1564,7 +1601,7 @@ func testAccessApplicationWithZoneID(resourceID, zone, zoneID string) string {
func testAccessApplicationWithZoneIDUpdated(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1575,7 +1612,7 @@ func testAccessApplicationWithZoneIDUpdated(resourceID, zone, zoneID string) str
func testAccessApplicationWithMissingCORSMethods(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1590,7 +1627,7 @@ func testAccessApplicationWithMissingCORSMethods(resourceID, zone, zoneID string
func testAccessApplicationWithMissingCORSOrigins(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1605,7 +1642,7 @@ func testAccessApplicationWithMissingCORSOrigins(resourceID, zone, zoneID string
func testAccessApplicationWithInvalidSessionDuration(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1617,7 +1654,7 @@ func testAccessApplicationWithInvalidSessionDuration(resourceID, zone, zoneID st
func testAccessApplicationMisconfiguredCORSAllowAllOriginsWithCredentials(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1634,7 +1671,7 @@ func testAccessApplicationMisconfiguredCORSAllowAllOriginsWithCredentials(resour
func testAccessApplicationMisconfiguredCORSAllowWildcardOriginWithCredentials(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s-updated"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
@@ -1651,24 +1688,24 @@ func testAccessApplicationMisconfiguredCORSAllowWildcardOriginWithCredentials(re
func testAccCloudflareAccessApplicationConfigWithADefinedTag(rnd, zoneID, domain string, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_tag" "%[1]s" {
+resource "cloudflare_zero_trust_access_tag" "%[1]s" {
account_id = "%[4]s"
name = "%[1]s"
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
domain = "%[1]s.%[3]s"
type = "self_hosted"
session_duration = "24h"
- tags = [cloudflare_access_tag.%[1]s.id]
+ tags = [cloudflare_zero_trust_access_tag.%[1]s.id]
}
`, rnd, zoneID, domain, accountID)
}
func testAccCloudflareAccessApplicationSCIMConfigValidHttpBasic(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1686,7 +1723,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1695,7 +1732,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "httpbasic"
@@ -1720,7 +1757,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigValidOAuthBearerTokenNoMappings(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1738,7 +1775,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1747,7 +1784,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = false
remote_uri = "scim2.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = false
authentication {
scheme = "oauthbearertoken"
@@ -1760,7 +1797,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigValidOAuthBearerToken(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1778,7 +1815,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1787,7 +1824,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "oauthbearertoken"
@@ -1811,7 +1848,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigValidOAuth2(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1829,7 +1866,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1838,7 +1875,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "oauth2"
@@ -1866,7 +1903,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigOAuth2MissingRequired(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1884,7 +1921,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1893,7 +1930,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "oauth2"
@@ -1920,7 +1957,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigAuthenticationInvalid(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1938,7 +1975,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -1947,7 +1984,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "oauth2"
@@ -1978,7 +2015,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigHttpBasicMissingRequired(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -1996,7 +2033,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -2005,7 +2042,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "httpbasic"
@@ -2028,7 +2065,7 @@ resource "cloudflare_access_application" "%[1]s" {
func testAccCloudflareAccessApplicationSCIMConfigInvalidMappingSchema(rnd, accountID, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "azureAD"
@@ -2046,7 +2083,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "self_hosted"
@@ -2055,7 +2092,7 @@ resource "cloudflare_access_application" "%[1]s" {
scim_config {
enabled = true
remote_uri = "scim.com"
- idp_uid = cloudflare_access_identity_provider.%[1]s.id
+ idp_uid = cloudflare_zero_trust_access_identity_provider.%[1]s.id
deactivate_on_delete = true
authentication {
scheme = "httpbasic"
@@ -2098,7 +2135,7 @@ resource "cloudflare_access_policy" "%[1]s_p2" {
}
}
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
domain = "%[1]s.%[2]s"
diff --git a/internal/sdkv2provider/resource_cloudflare_access_ca_certificate.go b/internal/sdkv2provider/resource_cloudflare_access_ca_certificate.go
index d0b967aa08..3dba3ae8fd 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_ca_certificate.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_ca_certificate.go
@@ -14,6 +14,25 @@ import (
)
func resourceCloudflareAccessCACertificate() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessCACertificateSchema(),
+ CreateContext: resourceCloudflareAccessCACertificateCreate,
+ ReadContext: resourceCloudflareAccessCACertificateRead,
+ UpdateContext: resourceCloudflareAccessCACertificateUpdate,
+ DeleteContext: resourceCloudflareAccessCACertificateDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessCACertificateImport,
+ },
+ Description: heredoc.Doc(`
+ Cloudflare Access can replace traditional SSH key models with
+ short-lived certificates issued to your users based on the token
+ generated by their Access login.
+ `),
+ DeprecationMessage: "`cloudflare_access_ca_certificate` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_short_lived_certificate` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessCACertificate() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessCACertificateSchema(),
CreateContext: resourceCloudflareAccessCACertificateCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_ca_certificate_test.go b/internal/sdkv2provider/resource_cloudflare_access_ca_certificate_test.go
index ad991bcab0..128efc2c10 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_ca_certificate_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_ca_certificate_test.go
@@ -16,7 +16,7 @@ func TestAccCloudflareAccessCACertificate_AccountLevel(t *testing.T) {
domain := os.Getenv("CLOUDFLARE_DOMAIN")
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_ca_certificate.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_short_lived_certificate.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -43,7 +43,7 @@ func TestAccCloudflareAccessCACertificate_ZoneLevel(t *testing.T) {
domain := os.Getenv("CLOUDFLARE_DOMAIN")
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_ca_certificate.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_short_lived_certificate.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -68,15 +68,15 @@ func TestAccCloudflareAccessCACertificate_ZoneLevel(t *testing.T) {
func testAccCloudflareAccessCACertificateBasic(resourceName, domain string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_application" "%[1]s" {
+resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
%[3]s_id = "%[4]s"
domain = "%[1]s.%[2]s"
}
-resource "cloudflare_access_ca_certificate" "%[1]s" {
+resource "cloudflare_zero_trust_access_short_lived_certificate" "%[1]s" {
%[3]s_id = "%[4]s"
- application_id = cloudflare_access_application.%[1]s.id
+ application_id = cloudflare_zero_trust_access_application.%[1]s.id
}`, resourceName, domain, identifier.Type, identifier.Identifier)
}
@@ -84,7 +84,7 @@ func testAccCheckCloudflareAccessCACertificateDestroy(s *terraform.State) error
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_ca_certificate" {
+ if rs.Type != "cloudflare_zero_trust_access_short_lived_certificate" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_access_custom_page.go b/internal/sdkv2provider/resource_cloudflare_access_custom_page.go
index 46428470ef..5b3734a14d 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_custom_page.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_custom_page.go
@@ -13,6 +13,21 @@ import (
)
func resourceCloudflareAccessCustomPage() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessCustomPageSchema(),
+ CreateContext: resourceCloudflareAccessCustomPageCreate,
+ ReadContext: resourceCloudflareAccessCustomPageRead,
+ UpdateContext: resourceCloudflareAccessCustomPageUpdate,
+ DeleteContext: resourceCloudflareAccessCustomPageDelete,
+ Description: heredoc.Doc(`
+ Provides a resource to customize the pages your end users will see
+ when trying to reach applications behind Cloudflare Access.
+ `),
+ DeprecationMessage: "`cloudflare_access_custom_page` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_custom_page` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessCustomPage() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessCustomPageSchema(),
CreateContext: resourceCloudflareAccessCustomPageCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_custom_page_test.go b/internal/sdkv2provider/resource_cloudflare_access_custom_page_test.go
index 42536baaf4..ba362e04b4 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_custom_page_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_custom_page_test.go
@@ -14,7 +14,7 @@ func TestAccCloudflareAccessCustomPage_IdentityDenied(t *testing.T) {
}
rnd := generateRandomResourceName()
- resourceName := fmt.Sprintf("cloudflare_access_custom_page.%s", rnd)
+ resourceName := fmt.Sprintf("cloudflare_zero_trust_access_custom_page.%s", rnd)
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
resource.Test(t, resource.TestCase{
@@ -41,7 +41,7 @@ func TestAccCloudflareAccessCustomPage_Forbidden(t *testing.T) {
}
rnd := generateRandomResourceName()
- resourceName := fmt.Sprintf("cloudflare_access_custom_page.%s", rnd)
+ resourceName := fmt.Sprintf("cloudflare_zero_trust_access_custom_page.%s", rnd)
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
resource.Test(t, resource.TestCase{
@@ -64,7 +64,7 @@ func TestAccCloudflareAccessCustomPage_Forbidden(t *testing.T) {
func testAccCheckCloudflareAccessCustomPage_CustomHTML(rnd, zoneID, pageType, markup string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_custom_page" "%[1]s" {
+resource "cloudflare_zero_trust_access_custom_page" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
type = "%[3]s"
diff --git a/internal/sdkv2provider/resource_cloudflare_access_group.go b/internal/sdkv2provider/resource_cloudflare_access_group.go
index 1ed49cd424..e650eb4add 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_group.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_group.go
@@ -15,6 +15,25 @@ import (
)
func resourceCloudflareAccessGroup() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessGroupSchema(),
+ CreateContext: resourceCloudflareAccessGroupCreate,
+ ReadContext: resourceCloudflareAccessGroupRead,
+ UpdateContext: resourceCloudflareAccessGroupUpdate,
+ DeleteContext: resourceCloudflareAccessGroupDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessGroupImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Access Group resource. Access Groups are used
+ in conjunction with Access Policies to restrict access to a
+ particular resource based on group membership.
+ `),
+ DeprecationMessage: "`cloudflare_access_group` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_group` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessGroup() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessGroupSchema(),
CreateContext: resourceCloudflareAccessGroupCreate,
@@ -411,8 +430,7 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
authMethod := ""
geos := []string{}
loginMethod := []string{}
- oktaID := ""
- oktaGroups := []string{}
+ oktaGroups := []map[string]interface{}{}
gsuiteID := ""
gsuiteEmails := []string{}
githubName := ""
@@ -488,8 +506,22 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
}
case "okta":
oktaCfg := groupValue.(map[string]interface{})
- oktaID = oktaCfg["identity_provider_id"].(string)
- oktaGroups = append(oktaGroups, oktaCfg["name"].(string))
+ oktaIdPID := oktaCfg["identity_provider_id"].(string)
+ oktaGroupName := oktaCfg["name"].(string)
+
+ var oktaGroup map[string]interface{}
+ for _, og := range oktaGroups {
+ if og["identity_provider_id"] == oktaIdPID {
+ oktaGroup = og
+ break
+ }
+ }
+
+ if len(oktaGroup) == 0 {
+ oktaGroups = append(oktaGroups, map[string]interface{}{"identity_provider_id": oktaIdPID, "name": []string{oktaGroupName}})
+ } else {
+ oktaGroup["name"] = append(oktaGroup["name"].([]string), oktaGroupName)
+ }
case "gsuite":
gsuiteCfg := groupValue.(map[string]interface{})
gsuiteID = gsuiteCfg["identity_provider_id"].(string)
@@ -605,13 +637,8 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
groupMap["login_method"] = loginMethod
}
- if len(oktaGroups) > 0 && oktaID != "" {
- groupMap["okta"] = []interface{}{
- map[string]interface{}{
- "identity_provider_id": oktaID,
- "name": oktaGroups,
- },
- }
+ if len(oktaGroups) > 0 {
+ groupMap["okta"] = oktaGroups
}
if len(gsuiteEmails) > 0 && gsuiteID != "" {
diff --git a/internal/sdkv2provider/resource_cloudflare_access_group_test.go b/internal/sdkv2provider/resource_cloudflare_access_group_test.go
index b52be33813..98d10abfa1 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_group_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_group_test.go
@@ -15,8 +15,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_access_group", &resource.Sweeper{
- Name: "cloudflare_access_group",
+ resource.AddTestSweepers("cloudflare_zero_trust_access_group", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_group",
F: testSweepCloudflareAccessGroups,
})
}
@@ -76,7 +76,7 @@ var (
func TestAccCloudflareAccessGroup_ConfigBasicZone(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -122,7 +122,7 @@ func TestAccCloudflareAccessGroup_ConfigBasicZone(t *testing.T) {
func TestAccCloudflareAccessGroup_ConfigBasicAccount(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -183,10 +183,10 @@ func TestAccCloudflareAccessGroup_ConfigBasicAccount(t *testing.T) {
func TestAccCloudflareAccessGroup_ConfigEmailList(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
rnd2 := generateRandomResourceName()
- emailListName := fmt.Sprintf("cloudflare_teams_list.%s", rnd2)
+ emailListName := fmt.Sprintf("cloudflare_zero_trust_list.%s", rnd2)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -214,7 +214,7 @@ func TestAccCloudflareAccessGroup_ConfigEmailList(t *testing.T) {
func TestAccCloudflareAccessGroup_Exclude(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -241,7 +241,7 @@ func TestAccCloudflareAccessGroup_Exclude(t *testing.T) {
func TestAccCloudflareAccessGroup_Require(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -268,7 +268,7 @@ func TestAccCloudflareAccessGroup_Require(t *testing.T) {
func TestAccCloudflareAccessGroup_FullConfig(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -299,7 +299,7 @@ func TestAccCloudflareAccessGroup_FullConfig(t *testing.T) {
func TestAccCloudflareAccessGroup_WithIDP(t *testing.T) {
rnd := generateRandomResourceName()
- groupName := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ groupName := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
githubOrg := "Terraform-Cloudflare-Provider-Test-Org"
team := "test-team-1"
@@ -328,7 +328,7 @@ func TestAccCloudflareAccessGroup_WithIDP(t *testing.T) {
func TestAccCloudflareAccessGroup_WithIDPAuthContext(t *testing.T) {
rnd := generateRandomResourceName()
- groupName := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ groupName := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
ctxID := generateRandomResourceName()
ctxACID := "c1"
@@ -358,7 +358,7 @@ func TestAccCloudflareAccessGroup_WithIDPAuthContext(t *testing.T) {
func TestAccCloudflareAccessGroup_Updated(t *testing.T) {
var before, after cloudflare.AccessGroup
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -390,7 +390,7 @@ func TestAccCloudflareAccessGroup_CreateAfterManualDestroy(t *testing.T) {
var before, after cloudflare.AccessGroup
var initialID string
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -426,7 +426,7 @@ func TestAccCloudflareAccessGroup_CreateAfterManualDestroy(t *testing.T) {
func TestAccCloudflareAccessGroup_UpdatedFromCommonNameToCommonNames(t *testing.T) {
var before, after cloudflare.AccessGroup
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_group.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_group.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -458,7 +458,7 @@ func TestAccCloudflareAccessGroup_UpdatedFromCommonNameToCommonNames(t *testing.
func testAccCloudflareAccessGroupConfigBasic(resourceName string, email string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[1]s"
@@ -496,7 +496,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccCloudflareAccessGroupConfigBasicWithUpdate(resourceName, accountID, email string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s-updated"
@@ -509,7 +509,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccessGroupConfigExclude(resourceName, accountID, email string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
@@ -526,7 +526,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccessGroupConfigRequire(resourceName, accountID, email string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
@@ -543,7 +543,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccessGroupConfigFullConfig(resourceName, accountID, email string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
@@ -565,7 +565,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccCloudflareAccessGroupWithIDP(accountID, rnd, githubOrg, team string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "github"
@@ -575,7 +575,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
}
}
-resource "cloudflare_access_group" "%[2]s" {
+resource "cloudflare_zero_trust_access_group" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
@@ -583,7 +583,7 @@ resource "cloudflare_access_group" "%[2]s" {
github {
name = "%[3]s"
teams = ["%[4]s"]
- identity_provider_id = cloudflare_access_identity_provider.%[2]s.id
+ identity_provider_id = cloudflare_zero_trust_access_identity_provider.%[2]s.id
}
}
}`, accountID, rnd, githubOrg, team)
@@ -591,7 +591,7 @@ resource "cloudflare_access_group" "%[2]s" {
func testAccCloudflareAccessGroupWithIDPAuthContext(accountID, rnd, authCtxID, authCtxACID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "azureAD"
@@ -602,7 +602,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
}
}
-resource "cloudflare_access_group" "%[2]s" {
+resource "cloudflare_zero_trust_access_group" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
@@ -614,7 +614,7 @@ resource "cloudflare_access_group" "%[2]s" {
auth_context {
id = "%[3]s"
ac_id = "%[4]s"
- identity_provider_id = cloudflare_access_identity_provider.%[2]s.id
+ identity_provider_id = cloudflare_zero_trust_access_identity_provider.%[2]s.id
}
}
}`, accountID, rnd, authCtxID, authCtxACID)
@@ -622,7 +622,7 @@ resource "cloudflare_access_group" "%[2]s" {
func testAccCloudflareAccessGroupConfigBasicWithCommonName(resourceName string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
%[2]s_id = "%[3]s"
name = "%[1]s"
@@ -634,7 +634,7 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccCloudflareAccessGroupConfigBasicWithCommonNames(resourceName string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
%[2]s_id = "%[3]s"
name = "%[1]s"
@@ -646,19 +646,19 @@ resource "cloudflare_access_group" "%[1]s" {
func testAccCloudflareAccessGroupConfigEmailList(resourceName string, emailListName string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_list" "%[2]s" {
+resource "cloudflare_zero_trust_list" "%[2]s" {
%[3]s_id = "%[4]s"
name = "%[2]s"
type = "EMAIL"
description = "Email list test for %[1]s"
items = [ "test@example.com" ]
}
-resource "cloudflare_access_group" "%[1]s" {
+resource "cloudflare_zero_trust_access_group" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[1]s"
include {
- email_list = [cloudflare_teams_list.%[2]s.id]
+ email_list = [cloudflare_zero_trust_list.%[2]s.id]
}
}`, resourceName, emailListName, identifier.Type, identifier.Identifier)
}
@@ -704,7 +704,7 @@ func testAccCheckCloudflareAccessGroupDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_group" {
+ if rs.Type != "cloudflare_zero_trust_access_group" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_access_identity_provider.go b/internal/sdkv2provider/resource_cloudflare_access_identity_provider.go
index 9d18293ce6..28d2f10d70 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_identity_provider.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_identity_provider.go
@@ -17,6 +17,25 @@ import (
const CONCEALED_STRING = "**********************************"
func resourceCloudflareAccessIdentityProvider() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessIdentityProviderSchema(),
+ CreateContext: resourceCloudflareAccessIdentityProviderCreate,
+ ReadContext: resourceCloudflareAccessIdentityProviderRead,
+ UpdateContext: resourceCloudflareAccessIdentityProviderUpdate,
+ DeleteContext: resourceCloudflareAccessIdentityProviderDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessIdentityProviderImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Access Identity Provider resource. Identity
+ Providers are used as an authentication or authorisation source
+ within Access.
+ `),
+ DeprecationMessage: "`cloudflare_access_identity_provider` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_identity_provider` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessIdentityProvider() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessIdentityProviderSchema(),
CreateContext: resourceCloudflareAccessIdentityProviderCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_identity_provider_test.go b/internal/sdkv2provider/resource_cloudflare_access_identity_provider_test.go
index 7bb0b85f7f..f05e857024 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_identity_provider_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_identity_provider_test.go
@@ -16,8 +16,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_access_identity_provider", &resource.Sweeper{
- Name: "cloudflare_access_identity_provider",
+ resource.AddTestSweepers("cloudflare_zero_trust_access_identity_provider", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_identity_provider",
F: testSweepCloudflareAccessIdentityProviders,
})
}
@@ -61,7 +61,7 @@ func TestAccCloudflareAccessIdentityProvider_OneTimePin(t *testing.T) {
}
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -114,7 +114,7 @@ func TestAccCloudflareAccessIdentityProvider_OAuth(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -140,7 +140,7 @@ func TestAccCloudflareAccessIdentityProvider_OAuthWithUpdate(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -176,7 +176,7 @@ func TestAccCloudflareAccessIdentityProvider_SAML(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -209,7 +209,7 @@ func TestAccCloudflareAccessIdentityProvider_AzureAD(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
@@ -240,7 +240,7 @@ func TestAccCloudflareAccessIdentityProvider_OAuth_Import(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
checkFn := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, consts.AccountIDSchemaKey, accountID),
@@ -276,7 +276,7 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Config_Secret(t *testing.T) {
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
checkFn := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrWith(resourceName, "scim_config.0.secret", func(value string) error {
@@ -315,7 +315,7 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Secret_Enabled_After_Resource_
t.Parallel()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- resourceName := "cloudflare_access_identity_provider." + rnd
+ resourceName := "cloudflare_zero_trust_access_identity_provider." + rnd
checkFn := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrWith(resourceName, "scim_config.0.secret", func(value string) error {
@@ -358,7 +358,7 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Secret_Enabled_After_Resource_
func testAccCheckCloudflareAccessIdentityProviderOneTimePin(name string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[1]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" {
%[2]s_id = "%[3]s"
name = "%[1]s"
type = "onetimepin"
@@ -367,7 +367,7 @@ resource "cloudflare_access_identity_provider" "%[1]s" {
func testAccCheckCloudflareAccessIdentityProviderOAuth(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "github"
@@ -380,7 +380,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
func testAccCheckCloudflareAccessIdentityProviderOAuthUpdatedName(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s-updated"
type = "github"
@@ -393,7 +393,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
func testAccCheckCloudflareAccessIdentityProviderSAML(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "saml"
@@ -409,7 +409,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
func testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "azureAD"
@@ -430,7 +430,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
func testAccCheckCloudflareAccessIdentityProviderAzureADUpdated(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "azureAD"
@@ -451,7 +451,7 @@ resource "cloudflare_access_identity_provider" "%[2]s" {
func testAccCheckCloudflareAccessIdentityProviderAzureADNoSCIM(accountID, name string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_identity_provider" "%[2]s" {
+resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
type = "azureAD"
diff --git a/internal/sdkv2provider/resource_cloudflare_access_keys_configuration.go b/internal/sdkv2provider/resource_cloudflare_access_keys_configuration.go
index 55d471d704..a97ae8541f 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_keys_configuration.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_keys_configuration.go
@@ -14,6 +14,24 @@ import (
)
func resourceCloudflareAccessKeysConfiguration() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessKeysConfigurationSchema(),
+ ReadContext: resourceCloudflareAccessKeysConfigurationRead,
+ CreateContext: resourceCloudflareAccessKeysConfigurationCreate,
+ UpdateContext: resourceCloudflareAccessKeysConfigurationUpdate,
+ DeleteContext: resourceCloudflareKeysConfigurationDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareKeysConfigurationImport,
+ },
+ Description: heredoc.Doc(`
+ Access Keys Configuration defines the rotation policy for the keys
+ that access will use to sign data.
+ `),
+ DeprecationMessage: "`cloudflare_access_keys_configuration` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_key_access_key_configuration` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessKeyConfiguration() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessKeysConfigurationSchema(),
ReadContext: resourceCloudflareAccessKeysConfigurationRead,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_keys_configuration_test.go b/internal/sdkv2provider/resource_cloudflare_access_keys_configuration_test.go
index 2833a3f3d4..269c9929b5 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_keys_configuration_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_keys_configuration_test.go
@@ -17,7 +17,7 @@ func TestAccCloudflareAccessKeysConfiguration_WithKeyRotationIntervalDaysSet(t *
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_keys_configuration.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_key_configuration.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -38,7 +38,7 @@ func TestAccCloudflareAccessKeysConfiguration_WithKeyRotationIntervalDaysSet(t *
func testAccessKeysConfigurationWithKeyRotationIntervalDays(rnd, accountID string, days int) string {
return fmt.Sprintf(`
-resource "cloudflare_access_keys_configuration" "%[1]s" {
+resource "cloudflare_zero_trust_access_key_configuration" "%[1]s" {
account_id = "%[2]s"
key_rotation_interval_days = "%[3]d"
}`, rnd, accountID, days)
@@ -53,7 +53,7 @@ func TestAccCloudflareAccessKeysConfiguration_WithoutKeyRotationIntervalDaysSet(
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_keys_configuration.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_key_configuration.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -74,7 +74,7 @@ func TestAccCloudflareAccessKeysConfiguration_WithoutKeyRotationIntervalDaysSet(
func testAccessKeysConfigurationWithoutKeyRotationIntervalDays(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_keys_configuration" "%[1]s" {
+resource "cloudflare_zero_trust_access_key_configuration" "%[1]s" {
account_id = "%[2]s"
}`, rnd, accountID)
}
diff --git a/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate.go b/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate.go
index 3e287c5ef9..1c48e36992 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate.go
@@ -15,6 +15,27 @@ import (
)
func resourceCloudflareAccessMutualTLSCertificate() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessMutualTLSCertificateSchema(),
+ CreateContext: resourceCloudflareAccessMutualTLSCertificateCreate,
+ ReadContext: resourceCloudflareAccessMutualTLSCertificateRead,
+ UpdateContext: resourceCloudflareAccessMutualTLSCertificateUpdate,
+ DeleteContext: resourceCloudflareAccessMutualTLSCertificateDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessMutualTLSCertificateImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Access Mutual TLS Certificate resource.
+ Mutual TLS authentication ensures that the traffic is secure and
+ trusted in both directions between a client and server and can be
+ used with Access to only allows requests from devices with a
+ corresponding client certificate.
+ `),
+ DeprecationMessage: "`cloudflare_access_mutual_tls_certificate` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_mtls_certificate` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessMutualTLSCertificate() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessMutualTLSCertificateSchema(),
CreateContext: resourceCloudflareAccessMutualTLSCertificateCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate_test.go b/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate_test.go
index a9ad4f7866..72ff7f6f1d 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_mutual_tls_certificate_test.go
@@ -14,8 +14,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_access_mutual_tls_certificate", &resource.Sweeper{
- Name: "cloudflare_access_mutual_tls_certificate",
+ resource.AddTestSweepers("cloudflare_zero_trust_access_mtls_certificate", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_access_mtls_certificate",
F: testSweepCloudflareAccessMutualTLSCertificate,
})
}
@@ -68,7 +68,7 @@ func TestAccCloudflareAccessMutualTLSBasic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_mutual_tls_certificate.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_mtls_certificate.%s", rnd)
cert := os.Getenv("CLOUDFLARE_MUTUAL_TLS_CERTIFICATE")
domain := os.Getenv("CLOUDFLARE_DOMAIN")
@@ -111,7 +111,7 @@ func TestAccCloudflareAccessMutualTLSBasicWithZoneID(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_mutual_tls_certificate.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_mtls_certificate.%s", rnd)
cert := os.Getenv("CLOUDFLARE_MUTUAL_TLS_CERTIFICATE")
domain := os.Getenv("CLOUDFLARE_DOMAIN")
@@ -148,7 +148,7 @@ func testAccCheckCloudflareAccessMutualTLSCertificateDestroy(s *terraform.State)
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_mutual_tls_certificate" {
+ if rs.Type != "cloudflare_zero_trust_access_mtls_certificate" {
continue
}
@@ -172,7 +172,7 @@ func testAccCheckCloudflareAccessMutualTLSCertificateDestroy(s *terraform.State)
func testAccessMutualTLSCertificateConfigBasic(rnd string, identifier *cloudflare.ResourceContainer, cert, domain string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_mutual_tls_certificate" "%[1]s" {
+resource "cloudflare_zero_trust_access_mtls_certificate" "%[1]s" {
name = "%[1]s"
%[2]s_id = "%[3]s"
associated_hostnames = ["%[5]s"]
@@ -183,7 +183,7 @@ resource "cloudflare_access_mutual_tls_certificate" "%[1]s" {
func testAccessMutualTLSCertificateUpdated(rnd string, identifier *cloudflare.ResourceContainer, cert string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_mutual_tls_certificate" "%[1]s" {
+resource "cloudflare_zero_trust_access_mtls_certificate" "%[1]s" {
name = "%[1]s"
%[2]s_id = "%[3]s"
associated_hostnames = []
diff --git a/internal/sdkv2provider/resource_cloudflare_access_organization.go b/internal/sdkv2provider/resource_cloudflare_access_organization.go
index f6d6f3edd2..51f5db7634 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_organization.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_organization.go
@@ -18,6 +18,23 @@ type contextKey int
const orgAccessImportCtxKey contextKey = iota
func resourceCloudflareAccessOrganization() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessOrganizationSchema(),
+ CreateContext: resourceCloudflareAccessOrganizationCreate,
+ ReadContext: resourceCloudflareAccessOrganizationRead,
+ UpdateContext: resourceCloudflareAccessOrganizationUpdate,
+ DeleteContext: resourceCloudflareAccessOrganizationNoop,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessOrganizationImport,
+ },
+ Description: heredoc.Doc(`
+ A Zero Trust organization defines the user login experience.
+ `),
+ DeprecationMessage: "`cloudflare_access_organization` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_organization` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessOrganization() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessOrganizationSchema(),
CreateContext: resourceCloudflareAccessOrganizationCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_organization_test.go b/internal/sdkv2provider/resource_cloudflare_access_organization_test.go
index e474791736..ee9febc55a 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_organization_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_organization_test.go
@@ -11,7 +11,7 @@ import (
func TestAccCloudflareAccessOrganization(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_organization.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_organization.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -80,7 +80,7 @@ func accessOrgImportStateCheck(instanceStates []*terraform.InstanceState) error
func testAccCloudflareAccessOrganizationConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_organization" "%[1]s" {
+ resource "cloudflare_zero_trust_organization" "%[1]s" {
account_id = "%[2]s"
name = "terraform-cfapi.cloudflareaccess.com"
auth_domain = "terraform-cfapi.cloudflareaccess.com1"
diff --git a/internal/sdkv2provider/resource_cloudflare_access_policy.go b/internal/sdkv2provider/resource_cloudflare_access_policy.go
index 92fe21c552..6c00dd6c6e 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_policy.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_policy.go
@@ -14,6 +14,25 @@ import (
)
func resourceCloudflareAccessPolicy() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessPolicySchema(),
+ CreateContext: resourceCloudflareAccessPolicyCreate,
+ ReadContext: resourceCloudflareAccessPolicyRead,
+ UpdateContext: resourceCloudflareAccessPolicyUpdate,
+ DeleteContext: resourceCloudflareAccessPolicyDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessPolicyImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Access Policy resource. Access Policies are
+ used in conjunction with Access Applications to restrict access to
+ a particular resource.
+ `),
+ DeprecationMessage: "`cloudflare_access_policy` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_policy` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessPolicy() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessPolicySchema(),
CreateContext: resourceCloudflareAccessPolicyCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_policy_test.go b/internal/sdkv2provider/resource_cloudflare_access_policy_test.go
index 4f38be3cc7..c741a0fccb 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_policy_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_policy_test.go
@@ -104,26 +104,26 @@ func TestAccCloudflareAccessPolicy_WithZoneID(t *testing.T) {
func testAccessPolicyServiceTokenConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
- resource "cloudflare_access_service_token" "%[1]s" {
+ resource "cloudflare_zero_trust_access_service_token" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "non_identity"
precedence = "10"
include {
- service_token = ["${cloudflare_access_service_token.%[1]s.id}"]
+ service_token = ["${cloudflare_zero_trust_access_service_token.%[1]s.id}"]
}
}
@@ -132,14 +132,14 @@ func testAccessPolicyServiceTokenConfig(resourceID, zone, accountID string) stri
func testAccessPolicyAnyServiceTokenConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "non_identity"
@@ -155,14 +155,14 @@ func testAccessPolicyAnyServiceTokenConfig(resourceID, zone, accountID string) s
func testAccessPolicyWithZoneID(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
zone_id = "%[3]s"
decision = "non_identity"
@@ -178,14 +178,14 @@ func testAccessPolicyWithZoneID(resourceID, zone, zoneID string) string {
func testAccessPolicyWithZoneIDUpdated(resourceID, zone, zoneID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
zone_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s-updated"
zone_id = "%[3]s"
decision = "non_identity"
@@ -226,13 +226,13 @@ func TestAccCloudflareAccessPolicy_Group(t *testing.T) {
func testAccessPolicyGroupConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
- resource "cloudflare_access_group" "%[1]s" {
+ resource "cloudflare_zero_trust_access_group" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
@@ -242,14 +242,14 @@ func testAccessPolicyGroupConfig(resourceID, zone, accountID string) string {
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "non_identity"
precedence = "10"
include {
- group = [cloudflare_access_group.%[1]s.id]
+ group = [cloudflare_zero_trust_access_group.%[1]s.id]
}
}
@@ -283,14 +283,14 @@ func TestAccCloudflareAccessPolicy_MTLS(t *testing.T) {
func testAccessPolicyMTLSConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "non_identity"
@@ -331,14 +331,14 @@ func TestAccCloudflareAccessPolicy_CommonName(t *testing.T) {
func testAccessPolicyCommonNameConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -380,14 +380,14 @@ func TestAccCloudflareAccessPolicy_EmailDomain(t *testing.T) {
func testAccessPolicyEmailDomainConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -431,14 +431,14 @@ func TestAccCloudflareAccessPolicy_Emails(t *testing.T) {
func testAccessPolicyEmailsConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -479,14 +479,14 @@ func TestAccCloudflareAccessPolicy_Everyone(t *testing.T) {
func testAccessPolicyEveryoneConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -529,14 +529,14 @@ func TestAccCloudflareAccessPolicy_IPs(t *testing.T) {
func testAccessPolicyIPsConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -577,14 +577,14 @@ func TestAccCloudflareAccessPolicy_AuthMethod(t *testing.T) {
func testAccessPolicyAuthMethodConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -627,14 +627,14 @@ func TestAccCloudflareAccessPolicy_Geo(t *testing.T) {
func testAccessPolicyGeoConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -678,14 +678,14 @@ func TestAccCloudflareAccessPolicy_Okta(t *testing.T) {
func testAccessPolicyOktaConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -767,14 +767,14 @@ func testAccCheckCloudflareAccessPolicyHasPJ(n string, accessIdentifier *cloudfl
func testAccessPolicyPurposeJustificationConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -886,14 +886,14 @@ func testAccCheckCloudflareAccessPolicyHasApprovalGroups(n string, accessIdentif
func testAccessPolicyApprovalGroupConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = "${cloudflare_access_application.%[1]s.id}"
+ application_id = "${cloudflare_zero_trust_access_application.%[1]s.id}"
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -948,14 +948,14 @@ func TestAccCloudflareAccessPolicy_ExternalEvaluation(t *testing.T) {
func testAccessPolicyExternalEvalautionConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = cloudflare_access_application.%[1]s.id
+ application_id = cloudflare_zero_trust_access_application.%[1]s.id
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
@@ -999,7 +999,7 @@ func TestAccCloudflareAccessPolicy_IsolationRequired(t *testing.T) {
func testAccessPolicyIsolationRequiredConfig(resourceID, zone, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_teams_account" "%[1]s" {
+ resource "cloudflare_zero_trust_gateway_settings" "%[1]s" {
account_id = "%[3]s"
tls_decrypt_enabled = true
protocol_detection_enabled = true
@@ -1058,15 +1058,15 @@ func testAccessPolicyIsolationRequiredConfig(resourceID, zone, accountID string)
}
}
- resource "cloudflare_access_application" "%[1]s" {
+ resource "cloudflare_zero_trust_access_application" "%[1]s" {
name = "%[1]s"
account_id = "%[3]s"
domain = "%[1]s.%[2]s"
- depends_on = ["cloudflare_teams_account.%[1]s"]
+ depends_on = ["cloudflare_zero_trust_gateway_settings.%[1]s"]
}
resource "cloudflare_access_policy" "%[1]s" {
- application_id = cloudflare_access_application.%[1]s.id
+ application_id = cloudflare_zero_trust_access_application.%[1]s.id
name = "%[1]s"
account_id = "%[3]s"
decision = "allow"
diff --git a/internal/sdkv2provider/resource_cloudflare_access_service_tokens.go b/internal/sdkv2provider/resource_cloudflare_access_service_tokens.go
index f4b3bb22b4..08bad92c32 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_service_tokens.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_service_tokens.go
@@ -14,6 +14,24 @@ import (
)
func resourceCloudflareAccessServiceToken() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessServiceTokenSchema(),
+ CreateContext: resourceCloudflareAccessServiceTokenCreate,
+ ReadContext: resourceCloudflareAccessServiceTokenRead,
+ UpdateContext: resourceCloudflareAccessServiceTokenUpdate,
+ DeleteContext: resourceCloudflareAccessServiceTokenDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareAccessServiceTokenImport,
+ },
+ Description: heredoc.Doc(`
+ Access Service Tokens are used for service-to-service communication
+ when an application is behind Cloudflare Access.
+ `),
+ DeprecationMessage: "`cloudflare_access_service_token` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_service_token` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessServiceToken() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessServiceTokenSchema(),
CreateContext: resourceCloudflareAccessServiceTokenCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_service_tokens_test.go b/internal/sdkv2provider/resource_cloudflare_access_service_tokens_test.go
index bae613a04e..5746f850ec 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_service_tokens_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_service_tokens_test.go
@@ -22,7 +22,7 @@ func TestAccCloudflareAccessServiceToken_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_service_token.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_service_token.%s", rnd)
resourceName := strings.Split(name, ".")[1]
resource.Test(t, resource.TestCase{
@@ -98,7 +98,7 @@ func TestAccCloudflareAccessServiceToken_Basic(t *testing.T) {
// rnd := generateRandomResourceName()
// var initialState terraform.ResourceState
-// name := fmt.Sprintf("cloudflare_access_service_token.%s", rnd)
+// name := fmt.Sprintf("cloudflare_zero_trust_access_service_token.%s", rnd)
// resourceName := strings.Split(name, ".")[1]
// expirationTime := 365
@@ -174,7 +174,7 @@ func TestAccCloudflareAccessServiceToken_Delete(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_service_token.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_service_token.%s", rnd)
resourceName := strings.Split(name, ".")[1]
resource.Test(t, resource.TestCase{
@@ -228,7 +228,7 @@ func TestAccCloudflareAccessServiceToken_WithDuration(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_access_service_token.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_access_service_token.%s", rnd)
resourceName := strings.Split(name, ".")[1]
resource.Test(t, resource.TestCase{
@@ -297,7 +297,7 @@ func TestAccCloudflareAccessServiceToken_WithDuration(t *testing.T) {
func testCloudflareAccessServiceTokenBasicConfig(resourceName string, tokenName string, identifier *cloudflare.ResourceContainer) string {
return fmt.Sprintf(`
-resource "cloudflare_access_service_token" "%[1]s" {
+resource "cloudflare_zero_trust_access_service_token" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[2]s"
min_days_for_renewal = "0"
@@ -306,7 +306,7 @@ resource "cloudflare_access_service_token" "%[1]s" {
func testCloudflareAccessServiceTokenBasicConfigWithDuration(resourceName string, tokenName string, identifier *cloudflare.ResourceContainer, duration string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_service_token" "%[1]s" {
+resource "cloudflare_zero_trust_access_service_token" "%[1]s" {
%[3]s_id = "%[4]s"
name = "%[2]s"
min_days_for_renewal = "0"
@@ -318,7 +318,7 @@ func testAccCheckCloudflareAccessServiceTokenDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_access_service_token" {
+ if rs.Type != "cloudflare_zero_trust_access_service_token" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_access_tag.go b/internal/sdkv2provider/resource_cloudflare_access_tag.go
index a748ac92c0..8da470219a 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_tag.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_tag.go
@@ -13,6 +13,21 @@ import (
)
func resourceCloudflareAccessTag() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareAccessTagSchema(),
+ CreateContext: resourceCloudflareAccessTagCreate,
+ ReadContext: resourceCloudflareAccessTagRead,
+ DeleteContext: resourceCloudflareAccessTagDelete,
+ UpdateContext: schema.NoopContext,
+ Description: heredoc.Doc(`
+ Provides a resource to customize the pages your end users will see
+ when trying to reach applications behind Cloudflare Access.
+ `),
+ DeprecationMessage: "`cloudflare_access_tag` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_access_tag` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustAccessTag() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccessTagSchema(),
CreateContext: resourceCloudflareAccessTagCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_access_tag_test.go b/internal/sdkv2provider/resource_cloudflare_access_tag_test.go
index 44297ca8a9..981a3156c9 100644
--- a/internal/sdkv2provider/resource_cloudflare_access_tag_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_access_tag_test.go
@@ -14,7 +14,7 @@ func TestAccCloudflareAccessTag_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- resourceName := fmt.Sprintf("cloudflare_access_tag.%s", rnd)
+ resourceName := fmt.Sprintf("cloudflare_zero_trust_access_tag.%s", rnd)
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
resource.Test(t, resource.TestCase{
@@ -36,7 +36,7 @@ func TestAccCloudflareAccessTag_Basic(t *testing.T) {
func testAccCheckCloudflareAccessTag(rnd, zoneID string) string {
return fmt.Sprintf(`
-resource "cloudflare_access_tag" "%[1]s" {
+resource "cloudflare_zero_trust_access_tag" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
}
diff --git a/internal/sdkv2provider/resource_cloudflare_custom_hostname_fallback_origin_test.go b/internal/sdkv2provider/resource_cloudflare_custom_hostname_fallback_origin_test.go
index 77ac5ace8f..dc1800c789 100644
--- a/internal/sdkv2provider/resource_cloudflare_custom_hostname_fallback_origin_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_custom_hostname_fallback_origin_test.go
@@ -12,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-testing/terraform"
)
-func TestAccCloudflareCustomHostnameFallbackOrigin(t *testing.T) {
+func TestAccCloudflareCustomHostname_FallbackOrigin(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the custom hostname
// fallback endpoint does not yet support the API tokens for updates and it
// results in state error messages.
@@ -50,7 +50,7 @@ resource "cloudflare_custom_hostname_fallback_origin" "%[2]s" {
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "fallback-origin.%[2]s.%[4]s"
- value = "example.com"
+ content = "example.com"
type = "CNAME"
proxied = true
ttl = 1
@@ -58,7 +58,7 @@ resource "cloudflare_record" "%[2]s" {
}`, zoneID, rnd, subdomain, domain)
}
-func TestAccCloudflareCustomHostnameFallbackOriginUpdate(t *testing.T) {
+func TestAccCloudflareCustomHostname_FallbackOriginUpdate(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the custom hostname
// fallback endpoint does not yet support the API tokens for updates and it
// results in state error messages.
diff --git a/internal/sdkv2provider/resource_cloudflare_custom_hostname_test.go b/internal/sdkv2provider/resource_cloudflare_custom_hostname_test.go
index a50eb2c5b0..bc8d015b2d 100644
--- a/internal/sdkv2provider/resource_cloudflare_custom_hostname_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_custom_hostname_test.go
@@ -220,7 +220,7 @@ resource "cloudflare_custom_hostname" "%[2]s" {
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "origin.%[2]s.terraform.cfapi.net"
- value = "example.com"
+ content = "example.com"
type = "CNAME"
ttl = 3600
}`, zoneID, rnd, domain)
@@ -283,7 +283,7 @@ func TestAccCloudflareCustomHostname_WithCustomSSLSettings(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "ssl.0.settings.0.http2", "off"),
resource.TestCheckResourceAttr(resourceName, "ssl.0.settings.0.min_tls_version", "1.2"),
resource.TestCheckResourceAttr(resourceName, "ssl.0.settings.0.ciphers.#", "2"),
- resource.TestCheckResourceAttr(resourceName, "ssl.0.certificate_authority", "lets_encrypt"),
+ resource.TestCheckResourceAttr(resourceName, "ssl.0.certificate_authority", "google"),
resource.TestCheckResourceAttrSet(resourceName, "ownership_verification.value"),
resource.TestCheckResourceAttrSet(resourceName, "ownership_verification.type"),
resource.TestCheckResourceAttrSet(resourceName, "ownership_verification.name"),
diff --git a/internal/sdkv2provider/resource_cloudflare_device_dex_tests.go b/internal/sdkv2provider/resource_cloudflare_device_dex_tests.go
index eb5c3f9053..ecfee93ba7 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_dex_tests.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_dex_tests.go
@@ -15,6 +15,21 @@ import (
)
func resourceCloudflareDeviceDexTest() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDeviceDexTestSchema(),
+ CreateContext: resourceCloudflareDeviceDexTestCreate,
+ ReadContext: resourceCloudflareDeviceDexTestRead,
+ UpdateContext: resourceCloudflareDeviceDexTestUpdate,
+ DeleteContext: resourceCloudflareDeviceDexTestDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDeviceDexTestImport,
+ },
+ Description: "Provides a Cloudflare Device Dex Test resource. Device Dex Tests allow for building location-aware device settings policies.",
+ DeprecationMessage: "`cloudflare_device_dex_test` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_dex_test` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDexTest() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDeviceDexTestSchema(),
CreateContext: resourceCloudflareDeviceDexTestCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_device_dex_tests_test.go b/internal/sdkv2provider/resource_cloudflare_device_dex_tests_test.go
index d5744edda2..98022be182 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_dex_tests_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_dex_tests_test.go
@@ -9,7 +9,7 @@ import (
func TestAccCloudflareDeviceDexTest_Traceroute(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_dex_test.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dex_test.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -35,7 +35,7 @@ func TestAccCloudflareDeviceDexTest_Traceroute(t *testing.T) {
func TestAccCloudflareDeviceDexTest_TracerouteIPv4(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_dex_test.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dex_test.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -61,7 +61,7 @@ func TestAccCloudflareDeviceDexTest_TracerouteIPv4(t *testing.T) {
func TestAccCloudflareDeviceDexTest_HTTP(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_dex_test.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dex_test.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -88,7 +88,7 @@ func TestAccCloudflareDeviceDexTest_HTTP(t *testing.T) {
func testAccCloudflareDeviceDexTestsHttp(accountID, rnd string) string {
return fmt.Sprintf(`
- resource "cloudflare_device_dex_test" "%[1]s" {
+ resource "cloudflare_zero_trust_dex_test" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "%[1]s"
@@ -105,7 +105,7 @@ func testAccCloudflareDeviceDexTestsHttp(accountID, rnd string) string {
func testAccCloudflareDeviceDexTestsTraceroute(accountID, rnd string) string {
return fmt.Sprintf(`
- resource "cloudflare_device_dex_test" "%[1]s" {
+ resource "cloudflare_zero_trust_dex_test" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "%[1]s"
@@ -121,7 +121,7 @@ func testAccCloudflareDeviceDexTestsTraceroute(accountID, rnd string) string {
func testAccCloudflareDeviceDexTestsTracerouteIpv4(accountID, rnd string) string {
return fmt.Sprintf(`
- resource "cloudflare_device_dex_test" "%[1]s" {
+ resource "cloudflare_zero_trust_dex_test" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "%[1]s"
diff --git a/internal/sdkv2provider/resource_cloudflare_device_managed_networks.go b/internal/sdkv2provider/resource_cloudflare_device_managed_networks.go
index 64472577f8..165cc75171 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_managed_networks.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_managed_networks.go
@@ -14,6 +14,21 @@ import (
)
func resourceCloudflareDeviceManagedNetworks() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDeviceManagedNetworksSchema(),
+ CreateContext: resourceCloudflareDeviceManagedNetworksCreate,
+ ReadContext: resourceCloudflareDeviceManagedNetworksRead,
+ UpdateContext: resourceCloudflareDeviceManagedNetworksUpdate,
+ DeleteContext: resourceCloudflareDeviceManagedNetworksDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDeviceManagedNetworksImport,
+ },
+ Description: "Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.",
+ DeprecationMessage: "`cloudflare_device_managed_networks` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_device_managed_networks` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDeviceManagedNetworks() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDeviceManagedNetworksSchema(),
CreateContext: resourceCloudflareDeviceManagedNetworksCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_device_managed_networks_test.go b/internal/sdkv2provider/resource_cloudflare_device_managed_networks_test.go
index 6faac36463..fefd65ce7d 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_managed_networks_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_managed_networks_test.go
@@ -10,7 +10,7 @@ import (
func TestAccCloudflareDeviceManagedNetworks(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_managed_networks.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_managed_networks.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -34,7 +34,7 @@ func TestAccCloudflareDeviceManagedNetworks(t *testing.T) {
func testAccCloudflareDeviceManagedNetworks(accountID, rnd string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_managed_networks" "%[1]s" {
+resource "cloudflare_zero_trust_device_managed_networks" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "tls"
diff --git a/internal/sdkv2provider/resource_cloudflare_device_policy_certificates.go b/internal/sdkv2provider/resource_cloudflare_device_policy_certificates.go
index f305a288b4..b512ac1917 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_policy_certificates.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_policy_certificates.go
@@ -13,6 +13,24 @@ import (
)
func resourceCloudflareDevicePolicyCertificates() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDevicePolicyCertificatesSchema(),
+ CreateContext: resourceCloudflareDevicePolicyCertificateUpdate,
+ ReadContext: resourceCloudflareDevicePolicyCertificateRead,
+ UpdateContext: resourceCloudflareDevicePolicyCertificateUpdate,
+ DeleteContext: resourceCloudflareDevicePolicyCertificateDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDevicePolicyCertificateImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare device policy certificates resource. Device
+ policy certificate resources enable client device certificate
+ generation.
+ `),
+ DeprecationMessage: "`cloudflare_device_policy_certificates` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_device_certificates` instead.",
+ }
+}
+func resourceCloudflareZeroTrustDevicePolicyCertificates() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDevicePolicyCertificatesSchema(),
CreateContext: resourceCloudflareDevicePolicyCertificateUpdate,
diff --git a/internal/sdkv2provider/resource_cloudflare_device_policy_certificates_test.go b/internal/sdkv2provider/resource_cloudflare_device_policy_certificates_test.go
index bcd210fcef..790da5b023 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_policy_certificates_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_policy_certificates_test.go
@@ -18,7 +18,7 @@ func TestAccCloudflareDevicePolicyCertificatesCreate(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_policy_certificates.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_certificates.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -40,7 +40,7 @@ func TestAccCloudflareDevicePolicyCertificatesCreate(t *testing.T) {
func testCloudflareDevicePolicyCertificates(rnd, zoneID string, enable bool) string {
return fmt.Sprintf(`
-resource "cloudflare_device_policy_certificates" "%[1]s" {
+resource "cloudflare_zero_trust_device_certificates" "%[1]s" {
zone_id = "%[2]s"
enabled = "%[3]t"
}
diff --git a/internal/sdkv2provider/resource_cloudflare_device_posture_integration.go b/internal/sdkv2provider/resource_cloudflare_device_posture_integration.go
index d14864ddbc..49bd0eb047 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_posture_integration.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_posture_integration.go
@@ -25,6 +25,25 @@ const (
)
func resourceCloudflareDevicePostureIntegration() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDevicePostureIntegrationSchema(),
+ CreateContext: resourceCloudflareDevicePostureIntegrationCreate,
+ ReadContext: resourceCloudflareDevicePostureIntegrationRead,
+ UpdateContext: resourceCloudflareDevicePostureIntegrationUpdate,
+ DeleteContext: resourceCloudflareDevicePostureIntegrationDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDevicePostureIntegrationImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Device Posture Integration resource. Device
+ posture integrations configure third-party data providers for device
+ posture rules.
+ `),
+ DeprecationMessage: "`cloudflare_device_posture_integration` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_device_posture_integration` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDevicePostureIntegration() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDevicePostureIntegrationSchema(),
CreateContext: resourceCloudflareDevicePostureIntegrationCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_device_posture_integration_test.go b/internal/sdkv2provider/resource_cloudflare_device_posture_integration_test.go
index 3e99152e25..2084f02c27 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_posture_integration_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_posture_integration_test.go
@@ -21,7 +21,7 @@ func TestAccCloudflareDevicePostureIntegrationCreate(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_integration.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_integration.%s", rnd)
clientID := os.Getenv("CLOUDFLARE_WORKSPACE_ONE_CLIENT_ID")
clientSecret := os.Getenv("CLOUDFLARE_WORKSPACE_ONE_CLIENT_SECRET")
@@ -54,7 +54,7 @@ func TestAccCloudflareDevicePostureIntegrationCreate(t *testing.T) {
func testAccCloudflareDevicePostureIntegration(rnd, accountID, clientID, clientSecret, apiURL, authURL string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_integration" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_integration" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "workspace_one"
@@ -73,7 +73,7 @@ func testAccCheckCloudflareDevicePostureIntegrationDestroy(s *terraform.State) e
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_device_posture_integration" {
+ if rs.Type != "cloudflare_zero_trust_device_posture_integration" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_device_posture_rule.go b/internal/sdkv2provider/resource_cloudflare_device_posture_rule.go
index 316ccfb2c6..815cded771 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_posture_rule.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_posture_rule.go
@@ -16,6 +16,23 @@ import (
)
func resourceCloudflareDevicePostureRule() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDevicePostureRuleSchema(),
+ CreateContext: resourceCloudflareDevicePostureRuleCreate,
+ ReadContext: resourceCloudflareDevicePostureRuleRead,
+ UpdateContext: resourceCloudflareDevicePostureRuleUpdate,
+ DeleteContext: resourceCloudflareDevicePostureRuleDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDevicePostureRuleImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Device Posture Rule resource. Device posture rules configure security policies for device posture checks.
+ `),
+ DeprecationMessage: "`cloudflare_device_posture_rule` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_device_posture_rule` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDevicePostureRule() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDevicePostureRuleSchema(),
CreateContext: resourceCloudflareDevicePostureRuleCreate,
@@ -166,7 +183,7 @@ func setDevicePostureRuleInput(rule *cloudflare.DevicePostureRule, d *schema.Res
input.Path = p.(string)
}
if exists, ok := d.GetOk("input.0.exists"); ok {
- input.Exists = exists.(bool)
+ input.Exists = cloudflare.BoolPtr(exists.(bool))
}
if tp, ok := d.GetOk("input.0.thumbprint"); ok {
input.Thumbprint = tp.(string)
@@ -175,10 +192,10 @@ func setDevicePostureRuleInput(rule *cloudflare.DevicePostureRule, d *schema.Res
input.Sha256 = s.(string)
}
if running, ok := d.GetOk("input.0.running"); ok {
- input.Running = running.(bool)
+ input.Running = cloudflare.BoolPtr(running.(bool))
}
if require_all, ok := d.GetOk("input.0.require_all"); ok {
- input.RequireAll = require_all.(bool)
+ input.RequireAll = cloudflare.BoolPtr(require_all.(bool))
}
if check_disks, ok := d.GetOk("input.0.check_disks"); ok {
values := check_disks.(*schema.Set).List()
@@ -187,7 +204,7 @@ func setDevicePostureRuleInput(rule *cloudflare.DevicePostureRule, d *schema.Res
}
}
if enabled, ok := d.GetOk("input.0.enabled"); ok {
- input.Enabled = enabled.(bool)
+ input.Enabled = cloudflare.BoolPtr(enabled.(bool))
}
if version, ok := d.GetOk("input.0.version"); ok {
input.Version = version.(string)
@@ -250,10 +267,10 @@ func setDevicePostureRuleInput(rule *cloudflare.DevicePostureRule, d *schema.Res
input.NetworkStatus = networkStatus.(string)
}
if infected, ok := d.GetOk("input.0.infected"); ok {
- input.Infected = infected.(bool)
+ input.Infected = cloudflare.BoolPtr(infected.(bool))
}
if isActive, ok := d.GetOk("input.0.is_active"); ok {
- input.IsActive = isActive.(bool)
+ input.IsActive = cloudflare.BoolPtr(isActive.(bool))
}
if eidLastSeen, ok := d.GetOk("input.0.eid_last_seen"); ok {
input.EidLastSeen = eidLastSeen.(string)
@@ -264,6 +281,18 @@ func setDevicePostureRuleInput(rule *cloudflare.DevicePostureRule, d *schema.Res
if totalScore, ok := d.GetOk("input.0.total_score"); ok {
input.TotalScore = totalScore.(int)
}
+ if checkPrivateKey, ok := d.GetOk("input.0.check_private_key"); ok {
+ input.CheckPrivateKey = cloudflare.BoolPtr(checkPrivateKey.(bool))
+ }
+ if extendedKeyUsage, ok := d.GetOk("input.0.extended_key_usage"); ok {
+ values := extendedKeyUsage.(*schema.Set).List()
+ for _, value := range values {
+ input.ExtendedKeyUsage = append(input.ExtendedKeyUsage, value.(string))
+ }
+ }
+ if locations, ok := d.GetOk("input.0.locations"); ok {
+ input.Locations = locations.(cloudflare.CertificateLocations)
+ }
rule.Input = input
}
}
@@ -300,6 +329,21 @@ func convertMatchToSchema(matches []cloudflare.DevicePostureRuleMatch) []map[str
}
func convertInputToSchema(input cloudflare.DevicePostureRuleInput) []map[string]interface{} {
+
+ formatLocationsToSchema := []map[string]interface{}{}
+ if len(input.Locations.Paths) > 0 && len(input.Locations.TrustStores) > 0 {
+ loc := map[string]interface{}{}
+
+ if len(input.Locations.Paths) > 0 {
+ loc["paths"] = input.Locations.Paths
+ }
+ if len(input.Locations.TrustStores) > 0 {
+ loc["trust_stores"] = input.Locations.TrustStores
+ }
+
+ formatLocationsToSchema = []map[string]interface{}{loc}
+ }
+
m := map[string]interface{}{
"id": input.ID,
"path": input.Path,
@@ -333,6 +377,9 @@ func convertInputToSchema(input cloudflare.DevicePostureRuleInput) []map[string]
"eid_last_seen": input.EidLastSeen,
"risk_level": input.RiskLevel,
"total_score": input.TotalScore,
+ "check_private_key": input.CheckPrivateKey,
+ "extended_key_usage": input.ExtendedKeyUsage,
+ "locations": formatLocationsToSchema,
}
return []map[string]interface{}{m}
diff --git a/internal/sdkv2provider/resource_cloudflare_device_posture_rule_test.go b/internal/sdkv2provider/resource_cloudflare_device_posture_rule_test.go
index 5b268b1bc5..72908a8af5 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_posture_rule_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_posture_rule_test.go
@@ -21,7 +21,7 @@ func TestAccCloudflareDevicePostureRule_SerialNumber(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -54,7 +54,7 @@ func TestAccCloudflareDevicePostureRule_OsVersion(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -88,7 +88,7 @@ func TestAccCloudflareDevicePostureRule_OsVersionExtra(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -123,7 +123,7 @@ func TestAccCloudflareDevicePostureRule_LinuxOsDistro(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -158,7 +158,7 @@ func TestAccCloudflareDevicePostureRule_DomainJoined(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -191,7 +191,7 @@ func TestAccCloudflareDevicePostureRule_Firewall(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -226,7 +226,7 @@ func TestAccCloudflareDevicePostureRule_DiskEncryption_RequireAll(t *testing.T)
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -261,7 +261,7 @@ func TestAccCloudflareDevicePostureRule_DiskEncryption_CheckDisks(t *testing.T)
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_device_posture_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -289,9 +289,51 @@ func TestAccCloudflareDevicePostureRule_DiskEncryption_CheckDisks(t *testing.T)
})
}
+func TestAccCloudflareDevicePostureRule_Intune(t *testing.T) {
+ skipForDefaultAccount(t, "Assertion requires active Intune license.")
+
+ // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
+ // service does not yet support the API tokens and it results in
+ // misleading state error messages.
+ if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
+ t.Setenv("CLOUDFLARE_API_TOKEN", "")
+ }
+
+ if v := os.Getenv("CLOUDFLARE_DEVICE_POSTURE_INTUNE_CONNECTION_ID"); v == "" {
+ t.Fatal("CLOUDFLARE_DEVICE_POSTURE_INTUNE_CONNECTION_ID must be set for this acceptance test")
+ }
+
+ rnd := generateRandomResourceName()
+ name := fmt.Sprintf("cloudflare_zero_trust_device_posture_rule.%s", rnd)
+ connectionID := os.Getenv("CLOUDFLARE_DEVICE_POSTURE_INTUNE_CONNECTION_ID")
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ ProviderFactories: providerFactories,
+ CheckDestroy: testAccCheckCloudflareDevicePostureRuleDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareDevicePostureRuleIntune(rnd, accountID, connectionID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "type", "intune"),
+ resource.TestCheckResourceAttr(name, "description", "intune compliance status"),
+ resource.TestCheckResourceAttr(name, "schedule", "24h"),
+ resource.TestCheckResourceAttr(name, "expiration", "24h"),
+ resource.TestCheckResourceAttr(name, "match.0.platform", "mac"),
+ resource.TestCheckResourceAttr(name, "input.0.compliance_status", "compliant"),
+ resource.TestCheckResourceAttr(name, "input.0.connection_id", connectionID),
+ ),
+ },
+ },
+ })
+}
+
func testAccCloudflareDevicePostureRuleConfigSerialNumber(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "serial_number"
@@ -310,7 +352,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigOsVersion(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "os_version"
@@ -330,7 +372,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigOsVersionExtra(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "os_version"
@@ -351,7 +393,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigLinuxDistro(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "os_version"
@@ -373,7 +415,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigDomainJoined(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "domain_joined"
@@ -392,7 +434,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigDiskEncryptionRequireAll(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "disk_encryption"
@@ -411,7 +453,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigDiskEncryptionCheckDisks(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "disk_encryption"
@@ -431,7 +473,7 @@ resource "cloudflare_device_posture_rule" "%[1]s" {
func testAccCloudflareDevicePostureRuleConfigFirewall(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_posture_rule" "%[1]s" {
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "firewall"
@@ -452,7 +494,7 @@ func testAccCheckCloudflareDevicePostureRuleDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_device_posture_rule" {
+ if rs.Type != "cloudflare_zero_trust_device_posture_rule" {
continue
}
@@ -464,3 +506,23 @@ func testAccCheckCloudflareDevicePostureRuleDestroy(s *terraform.State) error {
return nil
}
+
+func testAccCloudflareDevicePostureRuleIntune(rnd, accountID, connectionID string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_device_posture_rule" "%[1]s" {
+ account_id = "%[2]s"
+ name = "%[1]s"
+ type = "intune"
+ description = "intune compliance status"
+ schedule = "24h"
+ expiration = "24h"
+ match {
+ platform = "mac"
+ }
+ input {
+ compliance_status = "compliant"
+ connection_id = "%[3]s"
+ }
+}
+`, rnd, accountID, connectionID)
+}
diff --git a/internal/sdkv2provider/resource_cloudflare_device_settings_policy.go b/internal/sdkv2provider/resource_cloudflare_device_settings_policy.go
index 59efc6aeed..52878ec5cb 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_settings_policy.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_settings_policy.go
@@ -13,6 +13,21 @@ import (
)
func resourceCloudflareDeviceSettingsPolicy() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDeviceSettingsPolicySchema(),
+ CreateContext: resourceCloudflareDeviceSettingsPolicyCreate,
+ ReadContext: resourceCloudflareDeviceSettingsPolicyRead,
+ UpdateContext: resourceCloudflareDeviceSettingsPolicyUpdate,
+ DeleteContext: resourceCloudflareDeviceSettingsPolicyDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDeviceSettingsPolicyImport,
+ },
+ Description: "Provides a Cloudflare Device Settings Policy resource. Device policies configure settings applied to WARP devices.",
+ DeprecationMessage: "`cloudflare_device_settings_policy` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_device_profiles` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDeviceProfiles() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDeviceSettingsPolicySchema(),
CreateContext: resourceCloudflareDeviceSettingsPolicyCreate,
@@ -59,6 +74,7 @@ func resourceCloudflareDeviceSettingsPolicyCreate(ctx context.Context, d *schema
Enabled: req.Enabled,
ExcludeOfficeIps: req.ExcludeOfficeIps,
Description: req.Description,
+ TunnelProtocol: req.TunnelProtocol,
})
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Cloudflare device settings policy %q: %w", accountID, err))
@@ -100,6 +116,7 @@ func resourceCloudflareDeviceSettingsPolicyUpdate(ctx context.Context, d *schema
Enabled: req.Enabled,
ExcludeOfficeIps: req.ExcludeOfficeIps,
Description: req.Description,
+ TunnelProtocol: req.TunnelProtocol,
})
} else {
_, err = client.UpdateDeviceSettingsPolicy(ctx, cloudflare.AccountIdentifier(accountID), cloudflare.UpdateDeviceSettingsPolicyParams{
@@ -119,6 +136,7 @@ func resourceCloudflareDeviceSettingsPolicyUpdate(ctx context.Context, d *schema
Enabled: req.Enabled,
ExcludeOfficeIps: req.ExcludeOfficeIps,
Description: req.Description,
+ TunnelProtocol: req.TunnelProtocol,
})
}
if err != nil {
@@ -181,6 +199,9 @@ func resourceCloudflareDeviceSettingsPolicyRead(ctx context.Context, d *schema.R
if err := d.Set("exclude_office_ips", policy.ExcludeOfficeIps); err != nil {
return diag.FromErr(fmt.Errorf("error parsing exclude_office_ips"))
}
+ if err := d.Set("tunnel_protocol", policy.TunnelProtocol); err != nil {
+ return diag.FromErr(fmt.Errorf("error parsing tunnel_protocol"))
+ }
// ignore setting forbidden fields for default policies
if policy.Name != nil {
if err := d.Set("name", policy.Name); err != nil {
@@ -270,6 +291,7 @@ func buildDeviceSettingsPolicyRequest(d *schema.ResourceData) (cloudflare.Device
Port: d.Get("service_mode_v2_port").(int),
},
ExcludeOfficeIps: cloudflare.BoolPtr(d.Get("exclude_office_ips").(bool)),
+ TunnelProtocol: cloudflare.StringPtr(d.Get("tunnel_protocol").(string)),
}
name := d.Get("name").(string)
diff --git a/internal/sdkv2provider/resource_cloudflare_device_settings_policy_test.go b/internal/sdkv2provider/resource_cloudflare_device_settings_policy_test.go
index efef20e194..594dc596b9 100644
--- a/internal/sdkv2provider/resource_cloudflare_device_settings_policy_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_device_settings_policy_test.go
@@ -25,7 +25,7 @@ func TestAccCloudflareDeviceSettingsPolicy_Create(t *testing.T) {
}
rnd, defaultRnd := generateRandomResourceName(), generateRandomResourceName()
- name, defaultName := fmt.Sprintf("cloudflare_device_settings_policy.%s", rnd), fmt.Sprintf("cloudflare_device_settings_policy.%s", defaultRnd)
+ name, defaultName := fmt.Sprintf("cloudflare_zero_trust_device_profiles.%s", rnd), fmt.Sprintf("cloudflare_zero_trust_device_profiles.%s", defaultRnd)
precedence := uint64(10)
resource.Test(t, resource.TestCase{
@@ -57,6 +57,7 @@ func TestAccCloudflareDeviceSettingsPolicy_Create(t *testing.T) {
resource.TestCheckResourceAttr(name, "support_url", "https://cloudflare.com"),
resource.TestCheckResourceAttr(name, "switch_locked", "true"),
resource.TestCheckResourceAttr(name, "exclude_office_ips", "true"),
+ resource.TestCheckResourceAttr(name, "tunnel_protocol", "wireguard"),
),
},
{
@@ -79,6 +80,7 @@ func TestAccCloudflareDeviceSettingsPolicy_Create(t *testing.T) {
resource.TestCheckResourceAttr(defaultName, "support_url", "https://cloudflare.com"),
resource.TestCheckResourceAttr(defaultName, "switch_locked", "true"),
resource.TestCheckResourceAttr(defaultName, "exclude_office_ips", "true"),
+ resource.TestCheckResourceAttr(defaultName, "tunnel_protocol", "wireguard"),
),
},
{
@@ -91,7 +93,7 @@ func TestAccCloudflareDeviceSettingsPolicy_Create(t *testing.T) {
func testAccCloudflareDeviceSettingsPolicy(rnd, accountID string, precedence uint64) string {
return fmt.Sprintf(`
-resource "cloudflare_device_settings_policy" "%[1]s" {
+resource "cloudflare_zero_trust_device_profiles" "%[1]s" {
account_id = "%[2]s"
allow_mode_switch = true
allow_updates = true
@@ -107,13 +109,14 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
support_url = "https://cloudflare.com"
switch_locked = true
exclude_office_ips = true
+ tunnel_protocol = "wireguard"
}
`, rnd, accountID, precedence, rnd)
}
func testAccCloudflareDefaultDeviceSettingsPolicy(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_settings_policy" "%[1]s" {
+resource "cloudflare_zero_trust_device_profiles" "%[1]s" {
account_id = "%[2]s"
default = true
name = "%[1]s"
@@ -128,6 +131,7 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
support_url = "https://cloudflare.com"
switch_locked = true
exclude_office_ips = true
+ tunnel_protocol = "wireguard"
}
`, rnd, accountID, rnd)
}
@@ -135,7 +139,7 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
// invalid configuration - not allowed to set match for default policies.
func testAccCloudflareInvalidDefaultDeviceSettingsPolicy(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_settings_policy" "%[1]s" {
+resource "cloudflare_zero_trust_device_profiles" "%[1]s" {
account_id = "%[2]s"
default = true
name = "%[1]s"
@@ -150,6 +154,7 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
switch_locked = true
match = "identity.email == \"foo@example.com\""
exclude_office_ips = true
+ tunnel_protocol = "wireguard"
}
`, rnd, accountID, rnd)
}
@@ -158,7 +163,7 @@ func testAccCheckCloudflareDeviceSettingsPolicyDestroy(s *terraform.State) error
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_device_settings_policy" {
+ if rs.Type != "cloudflare_zero_trust_device_profiles" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_dlp_profile.go b/internal/sdkv2provider/resource_cloudflare_dlp_profile.go
index 321c05bf54..e43e1a1343 100644
--- a/internal/sdkv2provider/resource_cloudflare_dlp_profile.go
+++ b/internal/sdkv2provider/resource_cloudflare_dlp_profile.go
@@ -16,6 +16,25 @@ import (
)
func resourceCloudflareDLPProfile() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareDLPProfileSchema(),
+ CreateContext: resourceCloudflareDLPProfileCreate,
+ ReadContext: resourceCloudflareDLPProfileRead,
+ UpdateContext: resourceCloudflareDLPProfileUpdate,
+ DeleteContext: resourceCloudflareDLPProfileDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareDLPProfileImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare DLP Profile resource. Data Loss Prevention profiles
+ are a set of entries that can be matched in HTTP bodies or files.
+ They are referenced in Zero Trust Gateway rules.
+ `),
+ DeprecationMessage: "`cloudflare_dlp_profile` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_dlp_profile` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDLPProfile() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDLPProfileSchema(),
CreateContext: resourceCloudflareDLPProfileCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_dlp_profile_test.go b/internal/sdkv2provider/resource_cloudflare_dlp_profile_test.go
index 2d157f1f12..438ff2cd01 100644
--- a/internal/sdkv2provider/resource_cloudflare_dlp_profile_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_dlp_profile_test.go
@@ -13,7 +13,7 @@ import (
func TestAccCloudflareDLPProfile_Custom(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_dlp_profile.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dlp_profile.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -41,7 +41,7 @@ func TestAccCloudflareDLPProfile_Custom(t *testing.T) {
func TestAccCloudflareDLPProfile_Custom_MultipleEntries(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_dlp_profile.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dlp_profile.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -81,7 +81,7 @@ func TestAccCloudflareDLPProfile_Custom_MultipleEntries(t *testing.T) {
func TestAccCloudflareDLPProfile_CustomWithAllowedMatchCount(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_dlp_profile.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dlp_profile.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -109,7 +109,7 @@ func TestAccCloudflareDLPProfile_CustomWithAllowedMatchCount(t *testing.T) {
func TestAccCloudflareDLPProfile_CustomWithOCREnabled(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_dlp_profile.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dlp_profile.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -138,7 +138,7 @@ func TestAccCloudflareDLPProfile_CustomWithOCREnabled(t *testing.T) {
func TestAccCloudflareDLPProfile_ContextAwareness(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_dlp_profile.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dlp_profile.%s", rnd)
enabled := true
files := true
@@ -176,7 +176,7 @@ func TestAccCloudflareDLPProfile_ContextAwareness(t *testing.T) {
func testAccCloudflareDLPProfileConfigCustom(accountID, rnd, description string) string {
return fmt.Sprintf(`
-resource "cloudflare_dlp_profile" "%[1]s" {
+resource "cloudflare_zero_trust_dlp_profile" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
description = "%[2]s"
@@ -196,7 +196,7 @@ resource "cloudflare_dlp_profile" "%[1]s" {
func testAccCloudflareDLPProfileConfigCustomMultipleEntries(accountID, rnd, description string) string {
return fmt.Sprintf(`
-resource "cloudflare_dlp_profile" "%[1]s" {
+resource "cloudflare_zero_trust_dlp_profile" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
description = "%[2]s"
@@ -224,7 +224,7 @@ resource "cloudflare_dlp_profile" "%[1]s" {
func testAccCloudflareDLPProfileConfigCustomWithAllowedMatchCount(accountID, rnd, description string, allowedMatchCount uint) string {
return fmt.Sprintf(`
-resource "cloudflare_dlp_profile" "%[1]s" {
+resource "cloudflare_zero_trust_dlp_profile" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
description = "%[2]s"
@@ -244,7 +244,7 @@ resource "cloudflare_dlp_profile" "%[1]s" {
func testAccCloudflareDLPProfileConfigCustomWithOCREnabled(accountID, rnd, description string, ocrEnabled bool) string {
return fmt.Sprintf(`
-resource "cloudflare_dlp_profile" "%[1]s" {
+resource "cloudflare_zero_trust_dlp_profile" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
description = "%[2]s"
@@ -265,7 +265,7 @@ resource "cloudflare_dlp_profile" "%[1]s" {
func testAccCloudflareDLPProfileConfigWithContextAwareness(accountID, rnd, description string, contextAwareness cloudflare.DLPContextAwareness) string {
return fmt.Sprintf(`
-resource "cloudflare_dlp_profile" "%[2]s" {
+resource "cloudflare_zero_trust_dlp_profile" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
description = "%[3]s"
diff --git a/internal/sdkv2provider/resource_cloudflare_fallback_domain.go b/internal/sdkv2provider/resource_cloudflare_fallback_domain.go
index 4f162e234e..cf4863a736 100644
--- a/internal/sdkv2provider/resource_cloudflare_fallback_domain.go
+++ b/internal/sdkv2provider/resource_cloudflare_fallback_domain.go
@@ -13,6 +13,26 @@ import (
)
func resourceCloudflareFallbackDomain() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareFallbackDomainSchema(),
+ ReadContext: resourceCloudflareFallbackDomainRead,
+ CreateContext: resourceCloudflareFallbackDomainUpdate, // Intentionally identical to Update as the resource is always present
+ UpdateContext: resourceCloudflareFallbackDomainUpdate,
+ DeleteContext: resourceCloudflareFallbackDomainDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareFallbackDomainImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Fallback Domain resource. Fallback domains are
+ used to ignore DNS requests to a given list of domains. These DNS
+ requests will be passed back to other DNS servers configured on
+ existing network interfaces on the device.
+ `),
+ DeprecationMessage: "`cloudflare_fallback_domain` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_local_fallback_domain` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustLocalFallbackDomain() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareFallbackDomainSchema(),
ReadContext: resourceCloudflareFallbackDomainRead,
diff --git a/internal/sdkv2provider/resource_cloudflare_fallback_domain_test.go b/internal/sdkv2provider/resource_cloudflare_fallback_domain_test.go
index a3430492c6..9f3df7eb37 100644
--- a/internal/sdkv2provider/resource_cloudflare_fallback_domain_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_fallback_domain_test.go
@@ -22,7 +22,7 @@ func TestAccCloudflareFallbackDomain_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_fallback_domain.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_local_domain_fallback.%s", rnd)
resource.Test(t, resource.TestCase{
CheckDestroy: testAccCheckCloudflareFallbackDomainDestroy,
@@ -55,7 +55,7 @@ func TestAccCloudflareFallbackDomain_DefaultPolicy(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_fallback_domain.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_local_domain_fallback.%s", rnd)
resource.Test(t, resource.TestCase{
CheckDestroy: testAccCheckCloudflareFallbackDomainDestroy,
@@ -99,7 +99,7 @@ func TestAccCloudflareFallbackDomain_WithAttachedPolicy(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_fallback_domain.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_local_domain_fallback.%s", rnd)
resource.Test(t, resource.TestCase{
CheckDestroy: testAccCheckCloudflareFallbackDomainDestroy,
@@ -125,7 +125,7 @@ func TestAccCloudflareFallbackDomain_WithAttachedPolicy(t *testing.T) {
func testAccCloudflareDefaultFallbackDomain(rnd, accountID string, description string, suffix string, dns_server string) string {
return fmt.Sprintf(`
-resource "cloudflare_fallback_domain" "%[1]s" {
+resource "cloudflare_zero_trust_local_domain_fallback" "%[1]s" {
account_id = "%[2]s"
domains {
description = "%[3]s"
@@ -138,7 +138,7 @@ resource "cloudflare_fallback_domain" "%[1]s" {
func testAccCloudflareFallbackDomain(rnd, accountID, description string, suffix string, dns_server string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_settings_policy" "%[1]s" {
+resource "cloudflare_zero_trust_device_profiles" "%[1]s" {
account_id = "%[2]s"
allow_mode_switch = true
allow_updates = true
@@ -154,16 +154,17 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
switch_locked = true
exclude_office_ips = false
description = "%[1]s"
+ tunnel_protocol = "wireguard"
}
-resource "cloudflare_fallback_domain" "%[1]s" {
+resource "cloudflare_zero_trust_local_domain_fallback" "%[1]s" {
account_id = "%[2]s"
domains {
description = "%[3]s"
suffix = "%[4]s"
dns_server = ["%[5]s"]
}
- policy_id = "${cloudflare_device_settings_policy.%[1]s.id}"
+ policy_id = "${cloudflare_zero_trust_device_profiles.%[1]s.id}"
}
`, rnd, accountID, description, suffix, dns_server)
}
@@ -172,7 +173,7 @@ func testAccCheckCloudflareFallbackDomainDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_fallback_domain" {
+ if rs.Type != "cloudflare_zero_trust_local_domain_fallback" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_filter.go b/internal/sdkv2provider/resource_cloudflare_filter.go
index 688f434534..0916199b30 100644
--- a/internal/sdkv2provider/resource_cloudflare_filter.go
+++ b/internal/sdkv2provider/resource_cloudflare_filter.go
@@ -30,11 +30,11 @@ func resourceCloudflareFilter() *schema.Resource {
for more details and available fields and operators.
`),
DeprecationMessage: heredoc.Doc(fmt.Sprintf(`
- %s resource is in a deprecation phase that will
- last for 14 months (July 1st, 2024). During this time period, this
- resource is still fully supported but you are strongly advised
- to move to the %s resource. For more information, see
- https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users.
+ %s resource is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still fully supported
+ but you are strongly advised to move to the %s resource.
+
+ For more information, see https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users.
`, "`cloudflare_filter`", "`cloudflare_ruleset`")),
}
}
diff --git a/internal/sdkv2provider/resource_cloudflare_firewall_rule.go b/internal/sdkv2provider/resource_cloudflare_firewall_rule.go
index 38c08e5a0e..7758e7d5dc 100644
--- a/internal/sdkv2provider/resource_cloudflare_firewall_rule.go
+++ b/internal/sdkv2provider/resource_cloudflare_firewall_rule.go
@@ -4,9 +4,10 @@ import (
"context"
"errors"
"fmt"
- "github.com/MakeNowJust/heredoc/v2"
"strings"
+ "github.com/MakeNowJust/heredoc/v2"
+
cloudflare "github.com/cloudflare/cloudflare-go"
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
"github.com/hashicorp/terraform-plugin-log/tflog"
@@ -34,11 +35,11 @@ func resourceCloudflareFirewallRule() *schema.Resource {
Rule.
`),
DeprecationMessage: heredoc.Doc(fmt.Sprintf(`
- %s resource is in a deprecation phase that will
- last for 14 months (July 1st, 2024). During this time period, this
- resource is still fully supported but you are strongly advised
- to move to the %s resource. For more information, see
- https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users.
+ %s resource is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still fully supported
+ but you are strongly advised to move to the %s resource.
+
+ For more information, see https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users.
`, "`cloudflare_firewall_rule`", "`cloudflare_ruleset`")),
}
}
diff --git a/internal/sdkv2provider/resource_cloudflare_gre_tunnel.go b/internal/sdkv2provider/resource_cloudflare_gre_tunnel.go
index 6346f591e4..a1476623ca 100644
--- a/internal/sdkv2provider/resource_cloudflare_gre_tunnel.go
+++ b/internal/sdkv2provider/resource_cloudflare_gre_tunnel.go
@@ -14,6 +14,21 @@ import (
)
func resourceCloudflareGRETunnel() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareGRETunnelSchema(),
+ CreateContext: resourceCloudflareGRETunnelCreate,
+ ReadContext: resourceCloudflareGRETunnelRead,
+ UpdateContext: resourceCloudflareGRETunnelUpdate,
+ DeleteContext: resourceCloudflareGRETunnelDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareGRETunnelImport,
+ },
+ Description: "Provides a resource, that manages GRE tunnels for Magic Transit.",
+ DeprecationMessage: "`cloudflare_gre_tunnel` is now deprecated and will be removed in the next major version. Use `cloudflare_magic_wan_gre_tunnel` instead.",
+ }
+}
+
+func resourceCloudflareMagicWANGRETunnel() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareGRETunnelSchema(),
CreateContext: resourceCloudflareGRETunnelCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_gre_tunnel_test.go b/internal/sdkv2provider/resource_cloudflare_gre_tunnel_test.go
index 02cfae1762..9cced10a21 100644
--- a/internal/sdkv2provider/resource_cloudflare_gre_tunnel_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_gre_tunnel_test.go
@@ -17,7 +17,7 @@ func TestAccCloudflareGRETunnelExists(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_gre_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_gre_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var Tunnel cloudflare.MagicTransitGRETunnel
@@ -73,7 +73,7 @@ func TestAccCloudflareGRETunnelUpdateDescription(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_gre_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_gre_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var Tunnel cloudflare.MagicTransitGRETunnel
@@ -104,7 +104,7 @@ func TestAccCloudflareGRETunnelUpdateMulti(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_gre_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_gre_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var Tunnel cloudflare.MagicTransitGRETunnel
@@ -151,7 +151,7 @@ func TestAccCloudflareGRETunnelUpdateMulti(t *testing.T) {
func testAccCheckCloudflareGRETunnelSimple(ID, name, description, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_gre_tunnel" "%[1]s" {
+ resource "cloudflare_magic_wan_gre_tunnel" "%[1]s" {
account_id = "%[4]s"
name = "%[2]s"
customer_gre_endpoint = "203.0.113.1"
@@ -168,7 +168,7 @@ func testAccCheckCloudflareGRETunnelSimple(ID, name, description, accountID stri
func testAccCheckCloudflareGRETunnelMultiUpdate(ID, name, description, accountID string) string {
return fmt.Sprintf(`
- resource "cloudflare_gre_tunnel" "%[1]s" {
+ resource "cloudflare_magic_wan_gre_tunnel" "%[1]s" {
account_id = "%[4]s"
name = "%[2]s"
customer_gre_endpoint = "203.0.113.2"
diff --git a/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel.go b/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel.go
index a16ad358be..c554ec70d5 100644
--- a/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel.go
+++ b/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel.go
@@ -15,6 +15,23 @@ import (
)
func resourceCloudflareIPsecTunnel() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareIPsecTunnelSchema(),
+ CreateContext: resourceCloudflareIPsecTunnelCreate,
+ ReadContext: resourceCloudflareIPsecTunnelRead,
+ UpdateContext: resourceCloudflareIPsecTunnelUpdate,
+ DeleteContext: resourceCloudflareIPsecTunnelDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareIPsecTunnelImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a resource, that manages IPsec tunnels for Magic Transit.
+ `),
+ DeprecationMessage: "`cloudflare_ipsec_tunnel` is now deprecated and will be removed in the next major version. Use `cloudflare_magic_wan_ipsec_tunnel` instead.",
+ }
+}
+
+func resourceCloudflareMagicWANIPsecTunnel() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareIPsecTunnelSchema(),
CreateContext: resourceCloudflareIPsecTunnelCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel_test.go b/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel_test.go
index 48805689bc..0ce29cb0b4 100644
--- a/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_ipsec_tunnel_test.go
@@ -17,7 +17,7 @@ func TestAccCloudflareIPsecTunnelExists(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_ipsec_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_ipsec_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
psk := "asdf1234"
@@ -77,7 +77,7 @@ func TestAccCloudflareIPsecTunnelUpdateDescription(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_ipsec_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_ipsec_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
psk := "asdf1234"
@@ -109,7 +109,7 @@ func TestAccCloudflareIPsecTunnelUpdatePsk(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_ipsec_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_ipsec_tunnel.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
psk := "asdf1234"
pskUpdated := "1234asd"
@@ -140,7 +140,7 @@ func TestAccCloudflareIPsecTunnelUpdatePsk(t *testing.T) {
func testAccCheckCloudflareIPsecTunnelSimple(ID, description, accountID, psk string) string {
return fmt.Sprintf(`
- resource "cloudflare_ipsec_tunnel" "%[1]s" {
+ resource "cloudflare_magic_wan_ipsec_tunnel" "%[1]s" {
account_id = "%[3]s"
name = "%[2]s"
customer_endpoint = "203.0.113.1"
diff --git a/internal/sdkv2provider/resource_cloudflare_load_balancer_pool_test.go b/internal/sdkv2provider/resource_cloudflare_load_balancer_pool_test.go
index 5f80118e39..fadbbc359f 100644
--- a/internal/sdkv2provider/resource_cloudflare_load_balancer_pool_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_load_balancer_pool_test.go
@@ -171,7 +171,7 @@ func TestAccCloudflareLoadBalancerPool_VirtualNetworkID(t *testing.T) {
tunnelRouteResID := generateRandomResourceName()
poolResID := generateRandomResourceName()
- vnetName := "cloudflare_tunnel_virtual_network." + vnetResID
+ vnetName := "cloudflare_zero_trust_tunnel_cloudflared_virtual_network." + vnetResID
poolName := "cloudflare_load_balancer_pool." + poolResID
resource.Test(t, resource.TestCase{
@@ -457,23 +457,23 @@ resource "cloudflare_load_balancer_pool" "%[1]s" {
func testAccCheckCloudflareLoadBalancerPoolConfigVirtualNetworkID(accountID, vnetResID, tunnelResID, tunnelRouteResID, poolResID string) string {
return fmt.Sprintf(`
-resource "cloudflare_tunnel_virtual_network" "%[2]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_virtual_network" "%[2]s" {
account_id = "%[1]s"
name = "my-tf-vnet-for-pool-%[2]s"
comment = "test"
}
-resource "cloudflare_tunnel" "%[3]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "%[3]s" {
account_id = "%[1]s"
name = "my-tf-tunnel-for-pool-%[3]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-resource "cloudflare_tunnel_route" "%[4]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "%[4]s" {
account_id = "%[1]s"
network = "192.0.2.1/32"
- virtual_network_id = cloudflare_tunnel_virtual_network.%[2]s.id
- tunnel_id = cloudflare_tunnel.%[3]s.id
+ virtual_network_id = cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%[2]s.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.%[3]s.id
comment = "test"
}
@@ -485,7 +485,7 @@ resource "cloudflare_load_balancer_pool" "%[5]s" {
origins {
name = "example-1"
address = "192.0.2.1"
- virtual_network_id = cloudflare_tunnel_route.%[4]s.virtual_network_id
+ virtual_network_id = cloudflare_zero_trust_tunnel_cloudflared_route.%[4]s.virtual_network_id
enabled = true
}
}`, accountID, vnetResID, tunnelResID, tunnelRouteResID, poolResID)
diff --git a/internal/sdkv2provider/resource_cloudflare_rate_limit.go b/internal/sdkv2provider/resource_cloudflare_rate_limit.go
index 3775d7e24c..8b9994dafe 100644
--- a/internal/sdkv2provider/resource_cloudflare_rate_limit.go
+++ b/internal/sdkv2provider/resource_cloudflare_rate_limit.go
@@ -30,11 +30,11 @@ func resourceCloudflareRateLimit() *schema.Resource {
specific types of requests/responses.
`),
DeprecationMessage: heredoc.Doc(fmt.Sprintf(`
- %s resource is in a deprecation phase that will
- last for 14 months (July 1st, 2024). During this time period, this
- resource is still fully supported but you are strongly advised
- to move to the %s resource. For more information, see
- https://developers.cloudflare.com/waf/reference/migration-guides/old-rate-limiting-deprecation/#relevant-changes-for-terraform-users.
+ %s resource is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still fully supported
+ but you are strongly advised to move to the %s resource.
+
+ For more information, see https://developers.cloudflare.com/waf/reference/migration-guides/old-rate-limiting-deprecation/#relevant-changes-for-terraform-users.
`, "`cloudflare_rate_limit`", "`cloudflare_ruleset`")),
}
}
diff --git a/internal/sdkv2provider/resource_cloudflare_record.go b/internal/sdkv2provider/resource_cloudflare_record.go
index 56ffb63829..d738ef95f7 100644
--- a/internal/sdkv2provider/resource_cloudflare_record.go
+++ b/internal/sdkv2provider/resource_cloudflare_record.go
@@ -26,7 +26,7 @@ func resourceCloudflareRecord() *schema.Resource {
StateContext: resourceCloudflareRecordImport,
},
Description: heredoc.Doc(`Provides a Cloudflare record resource.`),
- SchemaVersion: 2,
+ SchemaVersion: 3,
Schema: resourceCloudflareRecordSchema(),
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Second),
@@ -38,6 +38,11 @@ func resourceCloudflareRecord() *schema.Resource {
Upgrade: resourceCloudflareRecordStateUpgradeV2,
Version: 1,
},
+ {
+ Type: resourceCloudflareRecordV2().CoreConfigSchema().ImpliedType(),
+ Upgrade: resourceCloudflareRecordStateUpgradeV3,
+ Version: 2,
+ },
},
}
}
@@ -61,6 +66,11 @@ func resourceCloudflareRecordCreate(ctx context.Context, d *schema.ResourceData,
newRecord.Content = value.(string)
}
+ content, contentOk := d.GetOk("content")
+ if contentOk {
+ newRecord.Content = content.(string)
+ }
+
data, dataOk := d.GetOk("data")
tflog.Debug(ctx, fmt.Sprintf("Data found in config: %#v", data))
@@ -81,12 +91,6 @@ func resourceCloudflareRecordCreate(ctx context.Context, d *schema.ResourceData,
newRecord.Data = newDataMap
}
- if valueOk == dataOk {
- return diag.FromErr(fmt.Errorf(
- "either 'value' (present: %t) or 'data' (present: %t) must be provided",
- valueOk, dataOk))
- }
-
if priority, ok := d.GetOkExists("priority"); ok {
p := uint16(priority.(int))
newRecord.Priority = &p
@@ -234,7 +238,18 @@ func resourceCloudflareRecordRead(ctx context.Context, d *schema.ResourceData, m
d.SetId(record.ID)
d.Set("hostname", record.Name)
d.Set("type", record.Type)
- d.Set("value", record.Content)
+
+ _, valueOk := d.GetOk("value")
+ if valueOk {
+ d.Set("value", record.Content)
+ }
+
+ _, contentOk := d.GetOk("content")
+ _, datatOk := d.GetOk("data")
+ if contentOk || datatOk {
+ d.Set("content", record.Content)
+ }
+
d.Set("ttl", record.TTL)
d.Set("proxied", record.Proxied)
d.Set("created_on", record.CreatedOn.Format(time.RFC3339Nano))
@@ -259,12 +274,23 @@ func resourceCloudflareRecordRead(ctx context.Context, d *schema.ResourceData, m
func resourceCloudflareRecordUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
zoneID := d.Get(consts.ZoneIDSchemaKey).(string)
+ var contentValue string
+
+ value, valueOk := d.GetOk("value")
+ if valueOk {
+ contentValue = value.(string)
+ }
+
+ content, contentOk := d.GetOk("content")
+ if contentOk {
+ contentValue = content.(string)
+ }
updateRecord := cloudflare.UpdateDNSRecordParams{
ID: d.Id(),
Type: d.Get("type").(string),
Name: d.Get("name").(string),
- Content: d.Get("value").(string),
+ Content: contentValue,
}
data, dataOk := d.GetOk("data")
diff --git a/internal/sdkv2provider/resource_cloudflare_record_migrate.go b/internal/sdkv2provider/resource_cloudflare_record_migrate.go
index 3be4ed03f5..7e7a27cdad 100644
--- a/internal/sdkv2provider/resource_cloudflare_record_migrate.go
+++ b/internal/sdkv2provider/resource_cloudflare_record_migrate.go
@@ -2,8 +2,12 @@ package sdkv2provider
import (
"context"
+ "fmt"
+ "strings"
+ "github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
func resourceCloudflareRecordV1() *schema.Resource {
@@ -182,3 +186,315 @@ func resourceCloudflareRecordStateUpgradeV2(_ context.Context, rawState map[stri
rawState["data"] = []interface{}{rawState["data"]}
return rawState, nil
}
+
+func resourceCloudflareRecordV2() *schema.Resource {
+ return &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ consts.ZoneIDSchemaKey: {
+ Description: consts.ZoneIDSchemaDescription,
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ StateFunc: func(i interface{}) string {
+ return strings.ToLower(i.(string))
+ },
+
+ Description: "The name of the record.",
+ },
+
+ "hostname": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The FQDN of the record.",
+ },
+
+ "type": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ ValidateFunc: validation.StringInSlice([]string{"A", "AAAA", "CAA", "CNAME", "TXT", "SRV", "LOC", "MX", "NS", "SPF", "CERT", "DNSKEY", "DS", "NAPTR", "SMIMEA", "SSHFP", "TLSA", "URI", "PTR", "HTTPS", "SVCB"}, false),
+ Description: fmt.Sprintf("The type of the record. %s", renderAvailableDocumentationValuesStringSlice([]string{"A", "AAAA", "CAA", "CNAME", "TXT", "SRV", "LOC", "MX", "NS", "SPF", "CERT", "DNSKEY", "DS", "NAPTR", "SMIMEA", "SSHFP", "TLSA", "URI", "PTR", "HTTPS", "SVCB"})),
+ },
+
+ "value": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ConflictsWith: []string{"data"},
+ DiffSuppressFunc: suppressTrailingDots,
+ Description: "The value of the record.",
+ Deprecated: "`value` is deprecated in favour of `content` and will be removed in the next major release.",
+ },
+
+ "content": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ConflictsWith: []string{"data"},
+ DiffSuppressFunc: suppressTrailingDots,
+ Description: "The content of the record.",
+ },
+
+ "data": {
+ Type: schema.TypeList,
+ MaxItems: 1,
+ Optional: true,
+ ConflictsWith: []string{"value"},
+ Description: "Map of attributes that constitute the record value.",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ // Properties present in several record types
+ "algorithm": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "key_tag": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "flags": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "service": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "certificate": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "type": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "usage": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "selector": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "matching_type": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "weight": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+
+ // SRV record properties
+ "proto": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "priority": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "port": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "target": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // LOC record properties
+ "size": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+ "altitude": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+ "long_degrees": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "lat_degrees": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "precision_horz": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+ "precision_vert": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+ "long_direction": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "long_minutes": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "long_seconds": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+ "lat_direction": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "lat_minutes": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "lat_seconds": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ },
+
+ // DNSKEY record properties
+ "protocol": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "public_key": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // DS record properties
+ "digest_type": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "digest": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // NAPTR record properties
+ "order": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "preference": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "regex": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "replacement": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // SSHFP record properties
+ "fingerprint": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // URI record properties
+ "content": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ // CAA record properties
+ "tag": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+
+ "value": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ },
+ },
+ },
+
+ "ttl": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ Description: "The TTL of the record.",
+ },
+
+ "priority": {
+ Type: schema.TypeInt,
+ Optional: true,
+ DiffSuppressFunc: suppressPriority,
+ Description: "The priority of the record.",
+ },
+
+ "proxied": {
+ Optional: true,
+ Type: schema.TypeBool,
+ Description: "Whether the record gets Cloudflare's origin protection.",
+ },
+
+ "created_on": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The RFC3339 timestamp of when the record was created.",
+ },
+
+ "metadata": {
+ Type: schema.TypeMap,
+ Computed: true,
+ Description: "A key-value map of string metadata Cloudflare associates with the record.",
+ },
+
+ "modified_on": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The RFC3339 timestamp of when the record was last modified.",
+ },
+
+ "proxiable": {
+ Type: schema.TypeBool,
+ Computed: true,
+ Description: "Shows whether this record can be proxied.",
+ },
+
+ "allow_overwrite": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ Description: "Allow creation of this record in Terraform to overwrite an existing record, if any. This does not affect the ability to update the record in Terraform and does not prevent other resources within Terraform or manual changes outside Terraform from overwriting this record. **This configuration is not recommended for most environments**",
+ },
+
+ "comment": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "Comments or notes about the DNS record. This field has no effect on DNS responses.",
+ },
+
+ "tags": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Description: "Custom tags for the DNS record.",
+ },
+ },
+ }
+}
+
+func resourceCloudflareRecordStateUpgradeV3(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
+ rawState["value"] = rawState["content"]
+ return rawState, nil
+}
diff --git a/internal/sdkv2provider/resource_cloudflare_record_test.go b/internal/sdkv2provider/resource_cloudflare_record_test.go
index 44c5829a98..7297150291 100644
--- a/internal/sdkv2provider/resource_cloudflare_record_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_record_test.go
@@ -79,7 +79,7 @@ func TestAccCloudflareRecord_Basic(t *testing.T) {
testAccCheckCloudflareRecordDates(resourceName, &record, testStartTime),
resource.TestCheckResourceAttr(resourceName, "name", "tf-acctest-basic"),
resource.TestCheckResourceAttr(resourceName, consts.ZoneIDSchemaKey, zoneID),
- resource.TestCheckResourceAttr(resourceName, "value", "192.168.0.10"),
+ resource.TestCheckResourceAttr(resourceName, "content", "192.168.0.10"),
resource.TestCheckResourceAttr(resourceName, "hostname", fmt.Sprintf("tf-acctest-basic.%s", zoneName)),
resource.TestMatchResourceAttr(resourceName, consts.ZoneIDSchemaKey, regexp.MustCompile("^[a-z0-9]{32}$")),
resource.TestCheckResourceAttr(resourceName, "ttl", "3600"),
@@ -95,6 +95,33 @@ func TestAccCloudflareRecord_Basic(t *testing.T) {
})
}
+func TestAccCloudflareRecord_BasicValue(t *testing.T) {
+ t.Parallel()
+ zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
+ rnd := generateRandomResourceName()
+ resourceName := fmt.Sprintf("cloudflare_record.%s", rnd)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProviderFactories: providerFactories,
+ CheckDestroy: testAccCheckCloudflareRecordDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckCloudflareRecordConfigBasicUsingValue(zoneID, "tf-acctest-basic", rnd),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "value", "192.168.0.8"),
+ ),
+ },
+ {
+ Config: testAccCheckCloudflareRecordConfigBasicUsingValueUpdated(zoneID, "tf-acctest-basic", rnd),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "value", "192.168.0.9"),
+ ),
+ },
+ },
+ })
+}
+
func TestAccCloudflareRecord_CaseInsensitive(t *testing.T) {
t.Parallel()
var record cloudflare.DNSRecord
@@ -147,7 +174,7 @@ func TestAccCloudflareRecord_Apex(t *testing.T) {
testAccCheckCloudflareRecordAttributes(&record),
resource.TestCheckResourceAttr(resourceName, "name", "@"),
resource.TestCheckResourceAttr(resourceName, consts.ZoneIDSchemaKey, zoneID),
- resource.TestCheckResourceAttr(resourceName, "value", "192.168.0.10"),
+ resource.TestCheckResourceAttr(resourceName, "content", "192.168.0.10"),
),
},
},
@@ -170,7 +197,7 @@ func TestAccCloudflareRecord_LOC(t *testing.T) {
Config: testAccCheckCloudflareRecordConfigLOC(zoneID, "tf-acctest-loc", rnd),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareRecordExists(resourceName, &record),
- resource.TestCheckResourceAttr(resourceName, "value", "37 46 46.000 N 122 23 35.000 W 0.00 100.00 0.00 0.00"),
+ resource.TestCheckResourceAttr(resourceName, "content", "37 46 46.000 N 122 23 35.000 W 0.00 100.00 0.00 0.00"),
resource.TestCheckResourceAttr(resourceName, "proxiable", "false"),
resource.TestCheckResourceAttr(resourceName, "data.0.lat_degrees", "37"),
resource.TestCheckResourceAttr(resourceName, "data.0.lat_degrees", "37"),
@@ -210,15 +237,12 @@ func TestAccCloudflareRecord_SRV(t *testing.T) {
testAccCheckCloudflareRecordExists(resourceName, &record),
resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("_xmpp-client._tcp.%s", rnd)),
resource.TestCheckResourceAttr(resourceName, "hostname", fmt.Sprintf("_xmpp-client._tcp.%s.%s", rnd, domain)),
- resource.TestCheckResourceAttr(resourceName, "value", "0 5222 talk.l.google.com"),
+ resource.TestCheckResourceAttr(resourceName, "content", "0 5222 talk.l.google.com"),
resource.TestCheckResourceAttr(resourceName, "proxiable", "false"),
resource.TestCheckResourceAttr(resourceName, "data.0.priority", "5"),
resource.TestCheckResourceAttr(resourceName, "data.0.weight", "0"),
resource.TestCheckResourceAttr(resourceName, "data.0.port", "5222"),
resource.TestCheckResourceAttr(resourceName, "data.0.target", "talk.l.google.com"),
- resource.TestCheckResourceAttr(resourceName, "data.0.service", "_xmpp-client"),
- resource.TestCheckResourceAttr(resourceName, "data.0.proto", "_tcp"),
- resource.TestCheckResourceAttr(resourceName, "data.0.name", rnd+"."+domain),
),
},
},
@@ -280,7 +304,7 @@ func TestAccCloudflareRecord_Proxied(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "proxiable", "true"),
resource.TestCheckResourceAttr(resourceName, "proxied", "true"),
resource.TestCheckResourceAttr(resourceName, "type", "CNAME"),
- resource.TestCheckResourceAttr(resourceName, "value", domain),
+ resource.TestCheckResourceAttr(resourceName, "content", domain),
),
},
},
@@ -483,7 +507,7 @@ func TestAccCloudflareRecord_MXWithPriorityZero(t *testing.T) {
Config: testAccCheckCloudflareRecordConfigMXWithPriorityZero(zoneID, rnd, zoneName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "priority", "0"),
- resource.TestCheckResourceAttr(resourceName, "value", "mail.terraform.cfapi.net"),
+ resource.TestCheckResourceAttr(resourceName, "content", "mail.terraform.cfapi.net"),
),
},
},
@@ -578,7 +602,7 @@ func TestAccCloudflareRecord_MXNull(t *testing.T) {
Config: testAccCheckCloudflareRecordNullMX(zoneID, rnd),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "name", rnd),
- resource.TestCheckResourceAttr(name, "value", "."),
+ resource.TestCheckResourceAttr(name, "content", "."),
resource.TestCheckResourceAttr(name, "priority", "0"),
),
},
@@ -787,7 +811,33 @@ func testAccCheckCloudflareRecordConfigBasic(zoneID, name, rnd string) string {
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "192.168.0.10"
+ content = "192.168.0.10"
+ type = "A"
+ ttl = 3600
+ tags = ["tag1", "tag2"]
+ comment = "this is a comment"
+}`, zoneID, name, rnd)
+}
+
+func testAccCheckCloudflareRecordConfigBasicUsingValue(zoneID, name, rnd string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_record" "%[3]s" {
+ zone_id = "%[1]s"
+ name = "%[2]s"
+ value = "192.168.0.8"
+ type = "A"
+ ttl = 3600
+ tags = ["tag1", "tag2"]
+ comment = "this is a comment"
+}`, zoneID, name, rnd)
+}
+
+func testAccCheckCloudflareRecordConfigBasicUsingValueUpdated(zoneID, name, rnd string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_record" "%[3]s" {
+ zone_id = "%[1]s"
+ name = "%[2]s"
+ value = "192.168.0.9"
type = "A"
ttl = 3600
tags = ["tag1", "tag2"]
@@ -800,7 +850,7 @@ func testAccCheckCloudflareRecordConfigApex(zoneID, rnd string) string {
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "@"
- value = "192.168.0.10"
+ content = "192.168.0.10"
type = "A"
ttl = 3600
}`, zoneID, rnd)
@@ -840,9 +890,6 @@ resource "cloudflare_record" "%[2]s" {
weight = 0
port = 5222
target = "talk.l.google.com"
- service = "_xmpp-client"
- proto = "_tcp"
- name = "%[2]s.%[3]s"
}
type = "SRV"
ttl = 3600
@@ -869,7 +916,7 @@ func testAccCheckCloudflareRecordConfigProxied(zoneID, domain, name, rnd string)
resource "cloudflare_record" "%[4]s" {
zone_id = "%[1]s"
name = "%[3]s"
- value = "%[2]s"
+ content = "%[2]s"
type = "CNAME"
proxied = true
}`, zoneID, domain, name, rnd)
@@ -880,7 +927,7 @@ func testAccCheckCloudflareRecordConfigNewValue(zoneID, name, rnd string) string
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "192.168.0.11"
+ content = "192.168.0.11"
type = "A"
ttl = 3600
tags = ["updated_tag1", "updated_tag2"]
@@ -893,7 +940,7 @@ func testAccCheckCloudflareRecordConfigChangeType(zoneID, name, zoneName, rnd st
resource "cloudflare_record" "%[4]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "%[3]s"
+ content = "%[3]s"
type = "CNAME"
ttl = 3600
}`, zoneID, name, zoneName, rnd)
@@ -904,7 +951,7 @@ func testAccCheckCloudflareRecordConfigChangeHostname(zoneID, name, rnd string)
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[2]s-changed"
- value = "192.168.0.10"
+ content = "192.168.0.10"
type = "A"
ttl = 3600
}`, zoneID, name, rnd)
@@ -915,7 +962,7 @@ func testAccCheckCloudflareRecordConfigTtlValidation(zoneID, name, zoneName, rnd
resource "cloudflare_record" "%[4]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "%[3]s"
+ content = "%[3]s"
type = "CNAME"
proxied = true
ttl = 3600
@@ -927,7 +974,7 @@ func testAccCheckCloudflareRecordConfigExplicitProxied(zoneID, name, zoneName, p
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "%[3]s"
+ content = "%[3]s"
type = "CNAME"
proxied = %[4]s
ttl = %[5]s
@@ -939,7 +986,7 @@ func testAccCheckCloudflareRecordConfigMXWithPriorityZero(zoneID, name, zoneName
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "mail.terraform.cfapi.net"
+ content = "mail.terraform.cfapi.net"
type = "MX"
priority = 0
proxied = false
@@ -983,7 +1030,7 @@ func testAccCheckCloudflareRecordNullMX(zoneID, rnd string) string {
zone_id = "%[2]s"
type = "MX"
name = "%[1]s"
- value = "."
+ content = "."
priority = 0
}
`, rnd, zoneID)
@@ -994,7 +1041,7 @@ func testAccCheckCloudflareRecordConfigMultipleTags(zoneID, name, rnd string) st
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "192.168.0.10"
+ content = "192.168.0.10"
type = "A"
ttl = 3600
tags = ["tag1", "tag2"]
@@ -1007,7 +1054,7 @@ func testAccCheckCloudflareRecordConfigNoTags(zoneID, name, rnd string) string {
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[2]s"
- value = "192.168.0.10"
+ content = "192.168.0.10"
type = "A"
ttl = 3600
}`, zoneID, name, rnd)
diff --git a/internal/sdkv2provider/resource_cloudflare_spectrum_application_test.go b/internal/sdkv2provider/resource_cloudflare_spectrum_application_test.go
index 7e1c355a3b..6c5ceca559 100644
--- a/internal/sdkv2provider/resource_cloudflare_spectrum_application_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_spectrum_application_test.go
@@ -426,7 +426,7 @@ func testAccCheckCloudflareSpectrumApplicationConfigOriginDNS(zoneID, zoneName,
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[3]s.origin"
- value = "example.com"
+ content = "example.com"
type = "CNAME"
ttl = 3600
}
@@ -458,7 +458,7 @@ func testAccCheckCloudflareSpectrumApplicationConfigOriginPortRange(zoneID, zone
resource "cloudflare_record" "%[3]s" {
zone_id = "%[1]s"
name = "%[3]s.origin"
- value = "example.com"
+ content = "example.com"
type = "CNAME"
ttl = 3600
}
diff --git a/internal/sdkv2provider/resource_cloudflare_split_tunnel.go b/internal/sdkv2provider/resource_cloudflare_split_tunnel.go
index f30b3d1c6f..646fbe840b 100644
--- a/internal/sdkv2provider/resource_cloudflare_split_tunnel.go
+++ b/internal/sdkv2provider/resource_cloudflare_split_tunnel.go
@@ -14,6 +14,24 @@ import (
)
func resourceCloudflareSplitTunnel() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareSplitTunnelSchema(),
+ ReadContext: resourceCloudflareSplitTunnelRead,
+ CreateContext: resourceCloudflareSplitTunnelUpdate, // Intentionally identical to Update as the resource is always present
+ UpdateContext: resourceCloudflareSplitTunnelUpdate,
+ DeleteContext: resourceCloudflareSplitTunnelDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareSplitTunnelImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Split Tunnel resource. Split tunnels are used to either
+ include or exclude lists of routes from the WARP client's tunnel.
+ `),
+ DeprecationMessage: "`cloudflare_split_tunnel` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_split_tunnel` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustSplitTunnel() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareSplitTunnelSchema(),
ReadContext: resourceCloudflareSplitTunnelRead,
diff --git a/internal/sdkv2provider/resource_cloudflare_split_tunnel_test.go b/internal/sdkv2provider/resource_cloudflare_split_tunnel_test.go
index 203483d8d2..948239ea9f 100644
--- a/internal/sdkv2provider/resource_cloudflare_split_tunnel_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_split_tunnel_test.go
@@ -19,7 +19,7 @@ func TestAccCloudflareSplitTunnel_Include(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_split_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_split_tunnels.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -77,7 +77,7 @@ func TestAccCloudflareSplitTunnel_ConflictingTunnelProperties(t *testing.T) {
func testAccCloudflareDefaultSplitTunnelInclude(rnd, accountID string, description string, host string, mode string) string {
return fmt.Sprintf(`
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "%[5]s"
tunnels {
@@ -90,7 +90,7 @@ resource "cloudflare_split_tunnel" "%[1]s" {
func testAccCloudflareSplitTunnelInclude(rnd, accountID string, description string, host string, mode string) string {
return fmt.Sprintf(`
-resource "cloudflare_device_settings_policy" "%[1]s" {
+resource "cloudflare_zero_trust_device_profiles" "%[1]s" {
account_id = "%[2]s"
allow_mode_switch = true
allow_updates = true
@@ -105,9 +105,10 @@ resource "cloudflare_device_settings_policy" "%[1]s" {
support_url = "https://cloudflare.com"
switch_locked = true
exclude_office_ips = false
+ tunnel_protocol = "wireguard"
}
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "%[5]s"
tunnels {
@@ -120,7 +121,7 @@ resource "cloudflare_split_tunnel" "%[1]s" {
func testAccCloudflareSplitTunnelConflictingTunnelProperties(rnd, accountID string, description string, mode string) string {
return fmt.Sprintf(`
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "%[4]s"
tunnels {
@@ -141,7 +142,7 @@ func TestAccCloudflareSplitTunnel_Exclude(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_split_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_split_tunnels.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -190,7 +191,7 @@ func TestAccCloudflareSplitTunnel_IncludeTunnelOrdering(t *testing.T) {
func testAccCloudflareSplitTunnelExclude(rnd, accountID string, description string, host string, mode string) string {
return fmt.Sprintf(`
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "%[5]s"
tunnels {
@@ -203,7 +204,7 @@ resource "cloudflare_split_tunnel" "%[1]s" {
func testAccCloudflareDefaultSplitTunnelIncludeMultiplesOrdered(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "include"
tunnels {
@@ -221,7 +222,7 @@ resource "cloudflare_split_tunnel" "%[1]s" {
func testAccCloudflareDefaultSplitTunnelIncludeMultiplesFlippedOrder(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_split_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_split_tunnels" "%[1]s" {
account_id = "%[2]s"
mode = "include"
tunnels {
diff --git a/internal/sdkv2provider/resource_cloudflare_static_route.go b/internal/sdkv2provider/resource_cloudflare_static_route.go
index bedad85da9..7873f79bc9 100644
--- a/internal/sdkv2provider/resource_cloudflare_static_route.go
+++ b/internal/sdkv2provider/resource_cloudflare_static_route.go
@@ -15,6 +15,25 @@ import (
)
func resourceCloudflareStaticRoute() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareStaticRouteSchema(),
+ CreateContext: resourceCloudflareStaticRouteCreate,
+ ReadContext: resourceCloudflareStaticRouteRead,
+ UpdateContext: resourceCloudflareStaticRouteUpdate,
+ DeleteContext: resourceCloudflareStaticRouteDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareStaticRouteImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a resource, that manages Cloudflare static routes for Magic
+ Transit or Magic WAN. Static routes are used to route traffic
+ through GRE tunnels.
+ `),
+ DeprecationMessage: "`cloudflare_static_route` is now deprecated and will be removed in the next major version. Use `cloudflare_magic_wan_static_route` instead.",
+ }
+}
+
+func resourceCloudflareMagicWANStaticRoute() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareStaticRouteSchema(),
CreateContext: resourceCloudflareStaticRouteCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_static_route_test.go b/internal/sdkv2provider/resource_cloudflare_static_route_test.go
index 7aadc21c69..05bc41b172 100644
--- a/internal/sdkv2provider/resource_cloudflare_static_route_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_static_route_test.go
@@ -16,7 +16,7 @@ func TestAccCloudflareStaticRoute_Exists(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_static_route.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_static_route.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var StaticRoute cloudflare.MagicTransitStaticRoute
@@ -70,7 +70,7 @@ func TestAccCloudflareStaticRoute_UpdateDescription(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_static_route.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_static_route.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var StaticRoute cloudflare.MagicTransitStaticRoute
@@ -101,7 +101,7 @@ func TestAccCloudflareStaticRoute_UpdateWeight(t *testing.T) {
skipMagicTransitTestForNonConfiguredDefaultZone(t)
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_static_route.%s", rnd)
+ name := fmt.Sprintf("cloudflare_magic_wan_static_route.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var StaticRoute cloudflare.MagicTransitStaticRoute
@@ -141,7 +141,7 @@ func TestAccCloudflareStaticRoute_UpdateWeight(t *testing.T) {
func testAccCheckCloudflareStaticRouteSimple(ID, description, accountID string, weight int) string {
return fmt.Sprintf(`
- resource "cloudflare_static_route" "%[1]s" {
+ resource "cloudflare_magic_wan_static_route" "%[1]s" {
account_id = "%[3]s"
prefix = "10.100.0.0/24"
nexthop = "10.0.0.0"
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_accounts.go b/internal/sdkv2provider/resource_cloudflare_teams_accounts.go
index 0be8455639..ba26ca4713 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_accounts.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_accounts.go
@@ -16,6 +16,25 @@ import (
)
func resourceCloudflareTeamsAccount() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTeamsAccountSchema(),
+ ReadContext: resourceCloudflareTeamsAccountRead,
+ UpdateContext: resourceCloudflareTeamsAccountUpdate,
+ CreateContext: resourceCloudflareTeamsAccountUpdate,
+ // This resource is a top-level account configuration and cant be "deleted"
+ Delete: func(_ *schema.ResourceData, _ interface{}) error { return nil },
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTeamsAccountImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Teams Account resource. The Teams Account
+ resource defines configuration for secure web gateway.
+ `),
+ DeprecationMessage: "`cloudflare_teams_account` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_gateway_settings` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustGatewaySettings() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTeamsAccountSchema(),
ReadContext: resourceCloudflareTeamsAccountRead,
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_accounts_test.go b/internal/sdkv2provider/resource_cloudflare_teams_accounts_test.go
index 73c7dfc8bd..d9ba23d90f 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_accounts_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_accounts_test.go
@@ -18,7 +18,7 @@ func TestAccCloudflareTeamsAccounts_ConfigurationBasic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_account.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_settings.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -73,7 +73,7 @@ func TestAccCloudflareTeamsAccounts_ConfigurationBasic(t *testing.T) {
func testAccCloudflareTeamsAccountBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_account" "%[1]s" {
+resource "cloudflare_zero_trust_gateway_settings" "%[1]s" {
account_id = "%[2]s"
tls_decrypt_enabled = true
protocol_detection_enabled = true
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_list.go b/internal/sdkv2provider/resource_cloudflare_teams_list.go
index b383dc3fba..195d33c7c3 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_list.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_list.go
@@ -15,6 +15,25 @@ import (
)
func resourceCloudflareTeamsList() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTeamsListSchema(),
+ CreateContext: resourceCloudflareTeamsListCreate,
+ ReadContext: resourceCloudflareTeamsListRead,
+ UpdateContext: resourceCloudflareTeamsListUpdate,
+ DeleteContext: resourceCloudflareTeamsListDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTeamsListImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Teams List resource. Teams lists are
+ referenced when creating secure web gateway policies or device
+ posture rules.
+ `),
+ DeprecationMessage: "`cloudflare_teams_list` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_list` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustList() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTeamsListSchema(),
CreateContext: resourceCloudflareTeamsListCreate,
@@ -35,21 +54,28 @@ func resourceCloudflareTeamsList() *schema.Resource {
func resourceCloudflareTeamsListCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
+ accountID := d.Get(consts.AccountIDSchemaKey).(string)
+
newTeamsList := cloudflare.CreateTeamsListParams{
Name: d.Get("name").(string),
Type: d.Get("type").(string),
Description: d.Get("description").(string),
}
- itemValues := d.Get("items").(*schema.Set).List()
- for _, v := range itemValues {
- newTeamsList.Items = append(newTeamsList.Items, cloudflare.TeamsListItem{Value: v.(string)})
+ itemsWithoutDescription := d.Get("items").(*schema.Set).List()
+ itemsWithDescriptionValues := d.Get("items_with_description").(*schema.Set).List()
+ allItems := append([]interface{}{}, itemsWithoutDescription...)
+ allItems = append(allItems, itemsWithDescriptionValues...)
+ for _, v := range allItems {
+ item, err := convertItemCFTeamsListItems(v)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error creating Teams List for account %q: %w", accountID, err))
+ }
+ newTeamsList.Items = append(newTeamsList.Items, *item)
}
tflog.Debug(ctx, fmt.Sprintf("Creating Cloudflare Teams List from struct: %+v", newTeamsList))
- accountID := d.Get(consts.AccountIDSchemaKey).(string)
-
identifier := cloudflare.AccountIdentifier(accountID)
list, err := client.CreateTeamsList(ctx, identifier, newTeamsList)
if err != nil {
@@ -89,7 +115,14 @@ func resourceCloudflareTeamsListRead(ctx context.Context, d *schema.ResourceData
return diag.FromErr(fmt.Errorf("error finding Teams List %q: %w", d.Id(), err))
}
- d.Set("items", convertListItemsToSchema(listItems))
+ itemsWithoutDescription, itemsWithDescription := convertListItemsToSchema(listItems)
+ // items with description and without description are processed in separate attributes,
+ // so customers may mix and match these two formats instead of forcing them to adopt one style
+ // The provider will stitch these fields together before processing
+ // this was done to avoid having to specify all items in object format(which is clunky),
+ // since terraform can not implement mixed types atm.
+ d.Set("items", itemsWithoutDescription)
+ d.Set("items_with_description", itemsWithDescription)
return nil
}
@@ -192,13 +225,33 @@ func setListItemDiff(patchList *cloudflare.PatchTeamsListParams, oldItems, newIt
}
}
-func convertListItemsToSchema(listItems []cloudflare.TeamsListItem) []string {
- itemValues := []string{}
+func convertItemCFTeamsListItems(item any) (*cloudflare.TeamsListItem, error) {
+ switch item.(type) {
+ case string:
+ return &cloudflare.TeamsListItem{Description: "", Value: item.(string)}, nil
+ case map[string]interface{}:
+ return &cloudflare.TeamsListItem{Description: item.(map[string]interface{})["description"].(string), Value: item.(map[string]interface{})["value"].(string)}, nil
+ }
+
+ return nil, fmt.Errorf("invalid list item `%v`. Should be string OR {\"description\": .., \"value\": ..} object", item)
+}
+
+// this method returns array of list items without any description and map of items with description
+// and value separate.
+func convertListItemsToSchema(listItems []cloudflare.TeamsListItem) ([]string, []map[string]string) {
+ itemValuesWithDescription := []map[string]string{}
+ itemValuesWithoutDescription := []string{}
// The API returns items in reverse order so we iterate backwards for correct ordering.
for i := len(listItems) - 1; i >= 0; i-- {
item := listItems[i]
- itemValues = append(itemValues, item.Value)
+ if item.Description != "" {
+ itemValuesWithDescription = append(itemValuesWithDescription,
+ map[string]string{"value": item.Value, "description": item.Description},
+ )
+ } else {
+ itemValuesWithoutDescription = append(itemValuesWithoutDescription, item.Value)
+ }
}
- return itemValues
+ return itemValuesWithoutDescription, itemValuesWithDescription
}
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_list_test.go b/internal/sdkv2provider/resource_cloudflare_teams_list_test.go
index 5dedbac3c0..769738c4e4 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_list_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_list_test.go
@@ -23,7 +23,7 @@ func TestAccCloudflareTeamsList_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_list.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_list.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -47,6 +47,43 @@ func TestAccCloudflareTeamsList_Basic(t *testing.T) {
})
}
+func TestAccCloudflareTeamsList_BasicWithDescription(t *testing.T) {
+ // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
+ // service does not yet support the API tokens and it results in
+ // misleading state error messages.
+ if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
+ t.Setenv("CLOUDFLARE_API_TOKEN", "")
+ }
+
+ rnd := generateRandomResourceName()
+ name := fmt.Sprintf("cloudflare_zero_trust_list.%s", rnd)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ ProviderFactories: providerFactories,
+ CheckDestroy: testAccCheckCloudflareTeamsListDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareTeamsListConfigBasicWithDescription(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "type", "DOMAIN"),
+ resource.TestCheckResourceAttr(name, "description", "My description"),
+ resource.TestCheckResourceAttr(name, "items.#", "1"),
+ resource.TestCheckResourceAttr(name, "items_with_description.#", "2"),
+ resource.TestCheckResourceAttr(name, "items.0", "abcdef.com"),
+ resource.TestCheckResourceAttr(name, "items_with_description.0.value", "abcd.com"),
+ resource.TestCheckResourceAttr(name, "items_with_description.0.description", "test"),
+ resource.TestCheckResourceAttr(name, "items_with_description.1.value", "abcdefghijk.com"),
+ resource.TestCheckResourceAttr(name, "items_with_description.1.description", "test-2"),
+ ),
+ },
+ },
+ })
+}
func TestAccCloudflareTeamsList_LottaListItems(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
// service does not yet support the API tokens and it results in
@@ -56,7 +93,7 @@ func TestAccCloudflareTeamsList_LottaListItems(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_list.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_list.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -108,7 +145,7 @@ func TestAccCloudflareTeamsList_Reordered(t *testing.T) {
func testAccCloudflareTeamsListConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_list" "%[1]s" {
+resource "cloudflare_zero_trust_list" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "My description"
@@ -118,6 +155,19 @@ resource "cloudflare_teams_list" "%[1]s" {
`, rnd, accountID)
}
+func testAccCloudflareTeamsListConfigBasicWithDescription(rnd, accountID string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_list" "%[1]s" {
+ account_id = "%[2]s"
+ name = "%[1]s"
+ description = "My description"
+ type = "DOMAIN"
+ items = [ "abcdef.com"]
+ items_with_description = [{"value" : "abcd.com", "description": "test"}, {"value" : "abcdefghijk.com", "description": "test-2"}]
+}
+`, rnd, accountID)
+}
+
func testAccCloudflareTeamsListConfigBigItemCount(rnd, accountID string) string {
items := []string{}
for i := 0; i < 1000; i++ {
@@ -125,7 +175,7 @@ func testAccCloudflareTeamsListConfigBigItemCount(rnd, accountID string) string
}
return fmt.Sprintf(`
-resource "cloudflare_teams_list" "%[1]s" {
+resource "cloudflare_zero_trust_list" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "My description"
@@ -137,7 +187,7 @@ resource "cloudflare_teams_list" "%[1]s" {
func testAccCloudflareTeamsListConfigReorderedItems(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_list" "%[1]s" {
+resource "cloudflare_zero_trust_list" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
description = "My description"
@@ -151,7 +201,7 @@ func testAccCheckCloudflareTeamsListDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_teams_list" {
+ if rs.Type != "cloudflare_zero_trust_list" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_location.go b/internal/sdkv2provider/resource_cloudflare_teams_location.go
index 41d560fdc6..8fdb131eb1 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_location.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_location.go
@@ -14,6 +14,24 @@ import (
)
func resourceCloudflareTeamsLocation() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTeamsLocationSchema(),
+ CreateContext: resourceCloudflareTeamsLocationCreate,
+ ReadContext: resourceCloudflareTeamsLocationRead,
+ UpdateContext: resourceCloudflareTeamsLocationUpdate,
+ DeleteContext: resourceCloudflareTeamsLocationDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTeamsLocationImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Teams Location resource. Teams Locations are
+ referenced when creating secure web gateway policies.
+ `),
+ DeprecationMessage: "`cloudflare_teams_location` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_dns_location` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustDNSLocation() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTeamsLocationSchema(),
CreateContext: resourceCloudflareTeamsLocationCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_location_test.go b/internal/sdkv2provider/resource_cloudflare_teams_location_test.go
index 78d2d2a997..869900740b 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_location_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_location_test.go
@@ -21,7 +21,7 @@ func TestAccCloudflareTeamsLocationBasic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_location.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_dns_location.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -45,7 +45,7 @@ func TestAccCloudflareTeamsLocationBasic(t *testing.T) {
func testAccCloudflareTeamsLocationConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_location" "%[1]s" {
+resource "cloudflare_zero_trust_dns_location" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
}
@@ -56,7 +56,7 @@ func testAccCheckCloudflareTeamsLocationDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_teams_location" {
+ if rs.Type != "cloudflare_zero_trust_dns_location" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints.go b/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints.go
index 2184793291..e84c3d3324 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints.go
@@ -14,6 +14,25 @@ import (
)
func resourceCloudflareTeamsProxyEndpoint() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTeamsProxyEndpointSchema(),
+ CreateContext: resourceCloudflareTeamsProxyEndpointCreate,
+ ReadContext: resourceCloudflareTeamsProxyEndpointRead,
+ UpdateContext: resourceCloudflareTeamsProxyEndpointUpdate,
+ DeleteContext: resourceCloudflareTeamsProxyEndpointDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTeamsProxyEndpointImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Teams Proxy Endpoint resource. Teams Proxy
+ Endpoints are used for pointing proxy clients at Cloudflare Secure
+ Gateway.
+ `),
+ DeprecationMessage: "`cloudflare_teams_proxy_endpoint` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_gateway_proxy_endpoint` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustGatewayProxyEndpoint() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTeamsProxyEndpointSchema(),
CreateContext: resourceCloudflareTeamsProxyEndpointCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints_test.go b/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints_test.go
index f7c0a45960..f25a036307 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_proxy_endpoints_test.go
@@ -22,7 +22,7 @@ func TestAccCloudflareTeamsProxyEndpoint_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_proxy_endpoint.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_proxy_endpoint.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -46,7 +46,7 @@ func TestAccCloudflareTeamsProxyEndpoint_Basic(t *testing.T) {
func testAccCloudflareTeamsProxyEndpointConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_proxy_endpoint" "%[1]s" {
+resource "cloudflare_zero_trust_gateway_proxy_endpoint" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
ips = ["104.16.132.229/32"]
@@ -58,7 +58,7 @@ func testAccCheckCloudflareTeamsProxyEndpointDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_teams_proxy_endpoint" {
+ if rs.Type != "cloudflare_zero_trust_gateway_proxy_endpoint" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_rules.go b/internal/sdkv2provider/resource_cloudflare_teams_rules.go
index 8856dbc05d..00c7bd0caf 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_rules.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_rules.go
@@ -15,6 +15,21 @@ import (
)
func resourceCloudflareTeamsRule() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTeamsRuleSchema(),
+ ReadContext: resourceCloudflareTeamsRuleRead,
+ UpdateContext: resourceCloudflareTeamsRuleUpdate,
+ CreateContext: resourceCloudflareTeamsRuleCreate,
+ DeleteContext: resourceCloudflareTeamsRuleDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTeamsRuleImport,
+ },
+ Description: "Provides a Cloudflare Teams rule resource. Teams rules comprise secure web gateway policies.",
+ DeprecationMessage: "`cloudflare_teams_rule` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_gateway_policy` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustGatewayPolicy() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTeamsRuleSchema(),
ReadContext: resourceCloudflareTeamsRuleRead,
@@ -216,6 +231,7 @@ func flattenTeamsRuleSettings(d *schema.ResourceData, settings *cloudflare.Teams
settings.AuditSSH == nil &&
settings.NotificationSettings == nil &&
settings.ResolveDnsThroughCloudflare == nil &&
+ settings.IgnoreCNAMECategoryMatches == nil &&
settings.DnsResolverSettings == nil {
return nil
}
@@ -234,14 +250,20 @@ func flattenTeamsRuleSettings(d *schema.ResourceData, settings *cloudflare.Teams
"untrusted_cert": flattenTeamsUntrustedCertSettings(settings.UntrustedCertSettings),
"payload_log": flattenTeamsDlpPayloadLogSettings(settings.PayloadLog),
"notification_settings": flattenTeamsNotificationSettings(settings.NotificationSettings),
- "resolve_dns_through_cloudflare": settings.ResolveDnsThroughCloudflare,
- "dns_resolvers": flattenTeamsDnsResolverSettings(settings.DnsResolverSettings),
}
if settings.IPCategories {
result["ip_categories"] = true
}
+ if settings.IgnoreCNAMECategoryMatches != nil {
+ result["ignore_cname_category_matches"] = *settings.IgnoreCNAMECategoryMatches
+ }
+
+ if settings.ResolveDnsThroughCloudflare != nil {
+ result["resolve_dns_through_cloudflare"] = *settings.ResolveDnsThroughCloudflare
+ }
+
if settings.AllowChildBypass != nil {
result["allow_child_bypass"] = *settings.AllowChildBypass
}
@@ -254,6 +276,10 @@ func flattenTeamsRuleSettings(d *schema.ResourceData, settings *cloudflare.Teams
result["audit_ssh"] = flattenTeamsAuditSSHSettings(settings.AuditSSH)
}
+ if settings.DnsResolverSettings != nil {
+ result["dns_resolvers"] = flattenTeamsDnsResolverSettings(settings.DnsResolverSettings)
+ }
+
return []interface{}{result}
}
@@ -283,10 +309,16 @@ func inflateTeamsRuleSettings(settings interface{}) *cloudflare.TeamsRuleSetting
payloadLog := inflateTeamsDlpPayloadLogSettings(settingsMap["payload_log"].([]interface{}))
untrustedCertSettings := inflateTeamsUntrustedCertSettings(settingsMap["untrusted_cert"].([]interface{}))
notificationSettings := inflateTeamsNotificationSettings(settingsMap["notification_settings"])
- resolveDnsThroughCloudflare := settingsMap["resolve_dns_through_cloudflare"].(bool)
dnsResolverSettings := inflateTeamsDnsResolverSettings(settingsMap["dns_resolvers"].([]interface{}))
- return &cloudflare.TeamsRuleSettings{
+ ignoreCNAMECategoryMatches := readOptionalBooleanSettings(settingsMap, "ignore_cname_category_matches")
+ allowChildBypass := readOptionalBooleanSettings(settingsMap, "allow_child_bypass")
+ bypassParentRule := readOptionalBooleanSettings(settingsMap, "bypass_parent_rule")
+ resolveDnsThroughCloudflare := readOptionalBooleanSettings(settingsMap, "resolve_dns_through_cloudflare")
+ auditSSHSettings := inflateTeamsAuditSSHSettings(settingsMap["audit_ssh"].([]interface{}))
+ ipCategories := readOptionalBooleanSettings(settingsMap, "ip_categories")
+
+ result := &cloudflare.TeamsRuleSettings{
BlockPageEnabled: enabled,
BlockReason: reason,
OverrideIPs: overrideIPs,
@@ -302,7 +334,20 @@ func inflateTeamsRuleSettings(settings interface{}) *cloudflare.TeamsRuleSetting
NotificationSettings: notificationSettings,
ResolveDnsThroughCloudflare: &resolveDnsThroughCloudflare,
DnsResolverSettings: dnsResolverSettings,
+ IgnoreCNAMECategoryMatches: &ignoreCNAMECategoryMatches,
+ IPCategories: ipCategories,
+ AuditSSH: auditSSHSettings,
+ }
+
+ // set optional settings if present, so api won't complain
+ if allowChildBypass {
+ result.AllowChildBypass = &allowChildBypass
+ }
+ if bypassParentRule {
+ result.BypassParentRule = &bypassParentRule
}
+
+ return result
}
func flattenTeamsRuleBisoAdminControls(settings *cloudflare.TeamsBISOAdminControlSettings) []interface{} {
@@ -310,11 +355,12 @@ func flattenTeamsRuleBisoAdminControls(settings *cloudflare.TeamsBISOAdminContro
return nil
}
return []interface{}{map[string]interface{}{
- "disable_printing": settings.DisablePrinting,
- "disable_copy_paste": settings.DisableCopyPaste,
- "disable_download": settings.DisableDownload,
- "disable_upload": settings.DisableUpload,
- "disable_keyboard": settings.DisableKeyboard,
+ "disable_printing": settings.DisablePrinting,
+ "disable_copy_paste": settings.DisableCopyPaste,
+ "disable_download": settings.DisableDownload,
+ "disable_upload": settings.DisableUpload,
+ "disable_keyboard": settings.DisableKeyboard,
+ "disable_clipboard_redirection": settings.DisableClipboardRedirection,
}}
}
@@ -340,12 +386,14 @@ func inflateTeamsRuleBisoAdminControls(settings interface{}) *cloudflare.TeamsBI
disableDownload := settingsMap["disable_download"].(bool)
disableUpload := settingsMap["disable_upload"].(bool)
disableKeyboard := settingsMap["disable_keyboard"].(bool)
+ disableClipboardRedirection := settingsMap["disable_clipboard_redirection"].(bool)
return &cloudflare.TeamsBISOAdminControlSettings{
- DisablePrinting: disablePrinting,
- DisableCopyPaste: disableCopyPaste,
- DisableDownload: disableDownload,
- DisableUpload: disableUpload,
- DisableKeyboard: disableKeyboard,
+ DisablePrinting: disablePrinting,
+ DisableCopyPaste: disableCopyPaste,
+ DisableDownload: disableDownload,
+ DisableUpload: disableUpload,
+ DisableKeyboard: disableKeyboard,
+ DisableClipboardRedirection: disableClipboardRedirection,
}
}
@@ -641,3 +689,23 @@ func providerToApiRulePrecedence(provided int64, ruleName string) int64 {
func apiToProviderRulePrecedence(apiPrecedence uint64, ruleName string) int64 {
return (int64(apiPrecedence) - int64(hashCodeString(ruleName))%rulePrecedenceFactor) / rulePrecedenceFactor
}
+
+func readOptionalBooleanSettings(settingsMap map[string]any, name string) bool {
+ val, ok := settingsMap[name]
+ if !ok {
+ return false
+ }
+ return val.(bool)
+}
+
+func inflateTeamsAuditSSHSettings(settings interface{}) *cloudflare.AuditSSHRuleSettings {
+ settingsList := settings.([]interface{})
+ if len(settingsList) != 1 {
+ return nil
+ }
+ settingsMap := settingsList[0].(map[string]interface{})
+ logging := settingsMap["command_logging"].(bool)
+ return &cloudflare.AuditSSHRuleSettings{
+ CommandLogging: logging,
+ }
+}
diff --git a/internal/sdkv2provider/resource_cloudflare_teams_rules_test.go b/internal/sdkv2provider/resource_cloudflare_teams_rules_test.go
index 465376030b..256e4bc028 100644
--- a/internal/sdkv2provider/resource_cloudflare_teams_rules_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_teams_rules_test.go
@@ -21,7 +21,7 @@ func TestAccCloudflareTeamsRule_Basic(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_policy.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -57,7 +57,7 @@ func TestAccCloudflareTeamsRule_Basic(t *testing.T) {
func testAccCloudflareTeamsRuleConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_rule" "%[1]s" {
+resource "cloudflare_zero_trust_gateway_policy" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
description = "desc"
@@ -93,7 +93,7 @@ func TestAccCloudflareTeamsRule_NoSettings(t *testing.T) {
}
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_teams_rule.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_policy.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -125,7 +125,7 @@ func TestAccCloudflareTeamsRule_NoSettings(t *testing.T) {
func testAccCloudflareTeamsRuleConfigNoSettings(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_teams_rule" "%[1]s" {
+resource "cloudflare_zero_trust_gateway_policy" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
description = "desc"
@@ -141,7 +141,7 @@ func testAccCheckCloudflareTeamsRuleDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_teams_rule" {
+ if rs.Type != "cloudflare_zero_trust_gateway_policy" {
continue
}
@@ -153,3 +153,196 @@ func testAccCheckCloudflareTeamsRuleDestroy(s *terraform.State) error {
return nil
}
+
+func TestAccCloudflareTeamsRule_CustomResolver(t *testing.T) {
+ // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
+ // service does not yet support the API tokens and it results in
+ // misleading state error messages.
+ if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
+ t.Setenv("CLOUDFLARE_API_TOKEN", "")
+ }
+
+ rnd := generateRandomResourceName()
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_policy.%s", rnd)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ ProviderFactories: providerFactories,
+ CheckDestroy: testAccCheckCloudflareTeamsRuleDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareTeamsRuleConfigCustomResolver(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "description", "desc"),
+ resource.TestCheckResourceAttr(name, "precedence", "12302"),
+ resource.TestCheckResourceAttr(name, "action", "resolve"),
+ resource.TestCheckResourceAttr(name, "filters.0", "dns_resolver"),
+ resource.TestCheckResourceAttr(name, "traffic", "any(dns.domains[*] == \"example.com\")"),
+ resource.TestCheckResourceAttr(name, "rule_settings.#", "1"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.block_page_enabled", "false"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.0.ip", "1.34.4.4"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.1.ip", "1.34.4.5"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.2.ip", "1.34.4.6"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.0.ip", "2a09:bac1:76c0:1378::b:248"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.1.ip", "2a09:bac1:76c0:1378::b:148"),
+
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.0.port", "53"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.1.port", "30000"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.2.port", "200"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.0.port", "53"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.1.port", "53"),
+
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.0.vnet_id", "5fb4dfe1-4fe7-4ff4-980e-72f89dd9af9e"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.1.vnet_id", ""),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.2.vnet_id", ""),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.0.vnet_id", ""),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.1.vnet_id", ""),
+
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.0.route_through_private_network", "true"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.1.route_through_private_network", "false"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv4.2.route_through_private_network", "false"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.0.route_through_private_network", "false"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.dns_resolvers.0.ipv6.1.route_through_private_network", "false"),
+
+ resource.TestCheckResourceAttr(name, "rule_settings.0.untrusted_cert.0.action", "error"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.payload_log.0.enabled", "true"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCloudflareTeamsRuleConfigCustomResolver(rnd, accountID string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_gateway_policy" "%[1]s" {
+ name = "%[1]s"
+ account_id = "%[2]s"
+ description = "desc"
+ precedence = 12302
+ action = "resolve"
+ filters = ["dns_resolver"]
+ traffic = "any(dns.domains[*] == \"example.com\")"
+ rule_settings {
+ insecure_disable_dnssec_validation = false
+ untrusted_cert {
+ action = "error"
+ }
+ payload_log {
+ enabled = true
+ }
+ dns_resolvers {
+ ipv4 {
+ ip = "1.34.4.4"
+ port = 53
+ vnet_id = "5fb4dfe1-4fe7-4ff4-980e-72f89dd9af9e"
+ route_through_private_network = true
+ }
+ ipv4 {
+ ip = "1.34.4.5"
+ port = 30000
+ }
+ ipv4 {
+ ip = "1.34.4.6"
+ port = 200
+ }
+
+
+ ipv6 {
+ ip = "2a09:bac1:76c0:1378::b:248"
+ port = 53
+ }
+ ipv6 {
+ ip = "2a09:bac1:76c0:1378::b:148"
+ port = 53
+ }
+
+
+ }
+ }
+}
+`, rnd, accountID)
+}
+
+func TestAccCloudflareTeamsRule_WithClipboardRedirection(t *testing.T) {
+ // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
+ // service does not yet support the API tokens and it results in
+ // misleading state error messages.
+ if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
+ t.Setenv("CLOUDFLARE_API_TOKEN", "")
+ }
+
+ rnd := generateRandomResourceName()
+ name := fmt.Sprintf("cloudflare_zero_trust_gateway_policy.%s", rnd)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ ProviderFactories: providerFactories,
+ CheckDestroy: testAccCheckCloudflareTeamsRuleDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudflareTeamsRuleConfigWithClipboardRedirection(rnd, accountID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID),
+ resource.TestCheckResourceAttr(name, "name", rnd),
+ resource.TestCheckResourceAttr(name, "description", "desc"),
+ resource.TestCheckResourceAttr(name, "precedence", "12302"),
+ resource.TestCheckResourceAttr(name, "action", "block"),
+ resource.TestCheckResourceAttr(name, "filters.0", "dns"),
+ resource.TestCheckResourceAttr(name, "traffic", "any(dns.domains[*] == \"example.com\")"),
+ resource.TestCheckResourceAttr(name, "rule_settings.#", "1"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.block_page_enabled", "true"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.block_page_reason", "cuz"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.insecure_disable_dnssec_validation", "false"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.egress.0.ipv4", "203.0.113.1"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.egress.0.ipv6", "2001:db8::/32"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.untrusted_cert.0.action", "error"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.payload_log.0.enabled", "true"),
+ resource.TestCheckResourceAttr(name, "rule_settings.0.biso_admin_controls.0.disable_clipboard_redirection", "true"), // Check new parameter
+ ),
+ },
+ },
+ })
+}
+
+func testAccCloudflareTeamsRuleConfigWithClipboardRedirection(rnd, accountID string) string {
+ return fmt.Sprintf(`
+resource "cloudflare_zero_trust_gateway_policy" "%[1]s" {
+ name = "%[1]s"
+ account_id = "%[2]s"
+ description = "desc"
+ precedence = 12302
+ action = "block"
+ filters = ["dns"]
+ traffic = "any(dns.domains[*] == \"example.com\")"
+ rule_settings {
+ block_page_enabled = true
+ block_page_reason = "cuz"
+ insecure_disable_dnssec_validation = false
+ egress {
+ ipv4 = "203.0.113.1"
+ ipv6 = "2001:db8::/32"
+ }
+ untrusted_cert {
+ action = "error"
+ }
+ payload_log {
+ enabled = true
+ }
+ biso_admin_controls {
+ disable_printing = false
+ disable_copy_paste = false
+ disable_download = false
+ disable_upload = false
+ disable_keyboard = false
+ disable_clipboard_redirection = true // Set new parameter
+ }
+ }
+}
+`, rnd, accountID)
+}
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel.go b/internal/sdkv2provider/resource_cloudflare_tunnel.go
index ee8bb28625..1e07bb30fd 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel.go
@@ -17,6 +17,24 @@ import (
const argoTunnelCNAME = "cfargotunnel.com"
func resourceCloudflareTunnel() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTunnelSchema(),
+ CreateContext: resourceCloudflareTunnelCreate,
+ ReadContext: resourceCloudflareTunnelRead,
+ DeleteContext: resourceCloudflareTunnelDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTunnelImport,
+ },
+ Description: heredoc.Doc(`
+ Tunnel exposes applications running on your local web server on any
+ network with an internet connection without manually adding DNS
+ records or configuring a firewall or router.
+ `),
+ DeprecationMessage: "`cloudflare_tunnel` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_cloudflared` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustTunnelCloudflared() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTunnelSchema(),
CreateContext: resourceCloudflareTunnelCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_config.go b/internal/sdkv2provider/resource_cloudflare_tunnel_config.go
index 0a67d8a26e..e8db232361 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_config.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_config.go
@@ -18,6 +18,23 @@ import (
)
func resourceCloudflareTunnelConfig() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTunnelConfigSchema(),
+ ReadContext: resourceCloudflareTunnelConfigRead,
+ CreateContext: resourceCloudflareTunnelConfigUpdate,
+ UpdateContext: resourceCloudflareTunnelConfigUpdate,
+ DeleteContext: resourceCloudflareTunnelConfigDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTunnelConfigImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a Cloudflare Tunnel configuration resource.
+ `),
+ DeprecationMessage: "`cloudflare_tunnel_config` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_cloudflared_config` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustTunnelCloudflaredConfig() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTunnelConfigSchema(),
ReadContext: resourceCloudflareTunnelConfigRead,
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_config_test.go b/internal/sdkv2provider/resource_cloudflare_tunnel_config_test.go
index 5e25c74356..0d18ed447b 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_config_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_config_test.go
@@ -11,15 +11,15 @@ import (
func testTunnelConfig(resourceID, accountID, tunnelSecret string) string {
return fmt.Sprintf(`
- resource "cloudflare_tunnel" "%[1]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
secret = "%[3]s"
}
- resource "cloudflare_tunnel_config" "%[1]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared_config" "%[1]s" {
account_id = "%[2]s"
- tunnel_id = cloudflare_tunnel.%[1]s.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.%[1]s.id
config {
warp_routing {
@@ -78,15 +78,15 @@ func testTunnelConfig(resourceID, accountID, tunnelSecret string) string {
func testTunnelConfigShort(resourceID, accountID, tunnelSecret string) string {
return fmt.Sprintf(`
- resource "cloudflare_tunnel" "%[1]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
secret = "%[3]s"
}
- resource "cloudflare_tunnel_config" "%[1]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared_config" "%[1]s" {
account_id = "%[2]s"
- tunnel_id = cloudflare_tunnel.%[1]s.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.%[1]s.id
config {
ingress_rule {
@@ -100,15 +100,15 @@ func testTunnelConfigShort(resourceID, accountID, tunnelSecret string) string {
func testTunnelConfigNilPointer(resourceID, accountID, tunnelSecret string) string {
return fmt.Sprintf(`
-resource "cloudflare_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
secret = "%[3]s"
}
-resource "cloudflare_tunnel_config" "%[1]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_config" "%[1]s" {
account_id = "%[2]s"
- tunnel_id = cloudflare_tunnel.%[1]s.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.%[1]s.id
config {
warp_routing {
@@ -130,7 +130,7 @@ resource "cloudflare_tunnel_config" "%[1]s" {
func TestAccCloudflareTunnelConfig_Full(t *testing.T) {
rnd := generateRandomResourceName()
- name := "cloudflare_tunnel_config." + rnd
+ name := "cloudflare_zero_trust_tunnel_cloudflared_config." + rnd
zoneID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
tunnelSecret := acctest.RandStringFromCharSet(32, acctest.CharSetAlpha)
@@ -200,7 +200,7 @@ func TestAccCloudflareTunnelConfig_Full(t *testing.T) {
func TestAccCloudflareTunnelConfig_Short(t *testing.T) {
rnd := generateRandomResourceName()
- name := "cloudflare_tunnel_config." + rnd
+ name := "cloudflare_zero_trust_tunnel_cloudflared_config." + rnd
zoneID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
tunnelSecret := acctest.RandStringFromCharSet(32, acctest.CharSetAlpha)
@@ -230,7 +230,7 @@ func TestAccCloudflareTunnelConfig_Short(t *testing.T) {
func TestAccCloudflareTunnelConfig_NilPointer(t *testing.T) {
rnd := generateRandomResourceName()
- name := "cloudflare_tunnel_config." + rnd
+ name := "cloudflare_zero_trust_tunnel_cloudflared_config." + rnd
zoneID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
tunnelSecret := acctest.RandStringFromCharSet(32, acctest.CharSetAlpha)
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_route.go b/internal/sdkv2provider/resource_cloudflare_tunnel_route.go
index 280734c4bb..05b49c48e4 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_route.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_route.go
@@ -15,6 +15,25 @@ import (
)
func resourceCloudflareTunnelRoute() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTunnelRouteSchema(),
+ CreateContext: resourceCloudflareTunnelRouteCreate,
+ ReadContext: resourceCloudflareTunnelRouteRead,
+ UpdateContext: resourceCloudflareTunnelRouteUpdate,
+ DeleteContext: resourceCloudflareTunnelRouteDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTunnelRouteImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a resource, that manages Cloudflare tunnel routes for Zero
+ Trust. Tunnel routes are used to direct IP traffic through
+ Cloudflare Tunnels.
+ `),
+ DeprecationMessage: "`cloudflare_tunnel_route` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_route` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustTunnelRoute() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTunnelRouteSchema(),
CreateContext: resourceCloudflareTunnelRouteCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_route_test.go b/internal/sdkv2provider/resource_cloudflare_tunnel_route_test.go
index 162cbe4ecd..e611e3f59a 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_route_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_route_test.go
@@ -16,8 +16,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_tunnel_route", &resource.Sweeper{
- Name: "cloudflare_tunnel_route",
+ resource.AddTestSweepers("cloudflare_zero_trust_tunnel_cloudflared_route", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_tunnel_cloudflared_route",
F: testSweepCloudflareTunnelRoute,
})
}
@@ -55,7 +55,7 @@ func testSweepCloudflareTunnelRoute(r string) error {
func TestAccCloudflareTunnelRoute_Exists(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel_route.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared_route.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var TunnelRoute cloudflare.TunnelRoute
@@ -111,7 +111,7 @@ func testAccCheckCloudflareTunnelRouteExists(name string, route *cloudflare.Tunn
func TestAccCloudflareTunnelRoute_UpdateComment(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel_route.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared_route.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var TunnelRoute cloudflare.TunnelRoute
@@ -143,15 +143,15 @@ func TestAccCloudflareTunnelRoute_UpdateComment(t *testing.T) {
func testAccCloudflareTunnelRouteSimple(ID, comment, accountID, network string) string {
return fmt.Sprintf(`
-resource "cloudflare_tunnel" "%[1]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
}
-resource "cloudflare_tunnel_route" "%[1]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_route" "%[1]s" {
account_id = "%[3]s"
- tunnel_id = cloudflare_tunnel.%[1]s.id
+ tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.%[1]s.id
network = "%[4]s"
comment = "%[2]s"
}`, ID, comment, accountID, network)
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_test.go b/internal/sdkv2provider/resource_cloudflare_tunnel_test.go
index c6a8577623..ea7c4b95c7 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_test.go
@@ -22,7 +22,7 @@ func TestAccCloudflareTunnelCreate_Basic(t *testing.T) {
accID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -45,7 +45,7 @@ func TestAccCloudflareTunnelCreate_Basic(t *testing.T) {
func testAccCheckCloudflareTunnelBasic(accID, name string) string {
return fmt.Sprintf(`
- resource "cloudflare_tunnel" "%[2]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
@@ -61,7 +61,7 @@ func TestAccCloudflareTunnelCreate_Managed(t *testing.T) {
accID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -85,7 +85,7 @@ func TestAccCloudflareTunnelCreate_Managed(t *testing.T) {
func testAccCheckCloudflareTunnelManaged(accID, name string) string {
return fmt.Sprintf(`
- resource "cloudflare_tunnel" "%[2]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
@@ -102,7 +102,7 @@ func TestAccCloudflareTunnelCreate_Unmanaged(t *testing.T) {
accID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -126,7 +126,7 @@ func TestAccCloudflareTunnelCreate_Unmanaged(t *testing.T) {
func testAccCheckCloudflareTunnelUnmanaged(accID, name string) string {
return fmt.Sprintf(`
- resource "cloudflare_tunnel" "%[2]s" {
+ resource "cloudflare_zero_trust_tunnel_cloudflared" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
@@ -136,7 +136,7 @@ func testAccCheckCloudflareTunnelUnmanaged(accID, name string) string {
func testAccCheckCloudflareTunnelDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_tunnel" {
+ if rs.Type != "cloudflare_zero_trust_tunnel_cloudflared" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network.go b/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network.go
index ef5445889c..acc37b85ea 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network.go
@@ -15,6 +15,26 @@ import (
)
func resourceCloudflareTunnelVirtualNetwork() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareTunnelVirtualNetworkSchema(),
+ CreateContext: resourceCloudflareTunnelVirtualNetworkCreate,
+ ReadContext: resourceCloudflareTunnelVirtualNetworkRead,
+ UpdateContext: resourceCloudflareTunnelVirtualNetworkUpdate,
+ DeleteContext: resourceCloudflareTunnelVirtualNetworkDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareTunnelVirtualNetworkImport,
+ },
+ Description: heredoc.Doc(`
+ Provides a resource, that manages Cloudflare tunnel virtual networks
+ for Zero Trust. Tunnel virtual networks are used for segregation of
+ Tunnel IP Routes via Virtualized Networks to handle overlapping
+ private IPs in your origins.
+ `),
+ DeprecationMessage: "`cloudflare_tunnel_virtual_network` is now deprecated and will be removed in the next major version. Use `cloudflare_zero_trust_tunnel_virtual_network` instead.",
+ }
+}
+
+func resourceCloudflareZeroTrustTunnelVirtualNetwork() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTunnelVirtualNetworkSchema(),
CreateContext: resourceCloudflareTunnelVirtualNetworkCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network_test.go b/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network_test.go
index 42a0599720..b751c43b03 100644
--- a/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_tunnel_virtual_network_test.go
@@ -16,8 +16,8 @@ import (
)
func init() {
- resource.AddTestSweepers("cloudflare_tunnel_virtual_network", &resource.Sweeper{
- Name: "cloudflare_tunnel_virtual_network",
+ resource.AddTestSweepers("cloudflare_zero_trust_tunnel_cloudflared_virtual_network", &resource.Sweeper{
+ Name: "cloudflare_zero_trust_tunnel_cloudflared_virtual_network",
F: testSweepCloudflareTunnelVirtualNetwork,
})
}
@@ -55,7 +55,7 @@ func testSweepCloudflareTunnelVirtualNetwork(r string) error {
func TestAccCloudflareTunnelVirtualNetwork_Exists(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel_virtual_network.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var TunnelVirtualNetwork cloudflare.TunnelVirtualNetwork
@@ -110,7 +110,7 @@ func testAccCheckCloudflareTunnelVirtualNetworkExists(name string, virtualNetwor
func TestAccCloudflareTunnelVirtualNetwork_UpdateComment(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_tunnel_virtual_network.%s", rnd)
+ name := fmt.Sprintf("cloudflare_zero_trust_tunnel_cloudflared_virtual_network.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
var TunnelVirtualNetwork cloudflare.TunnelVirtualNetwork
@@ -142,7 +142,7 @@ func TestAccCloudflareTunnelVirtualNetwork_UpdateComment(t *testing.T) {
func testAccCloudflareTunnelVirtualNetworkSimple(ID, comment, accountID, name string, isDefault bool) string {
return fmt.Sprintf(`
-resource "cloudflare_tunnel_virtual_network" "%[1]s" {
+resource "cloudflare_zero_trust_tunnel_cloudflared_virtual_network" "%[1]s" {
account_id = "%[3]s"
name = "%[4]s"
comment = "%[2]s"
diff --git a/internal/sdkv2provider/resource_cloudflare_waiting_room_test.go b/internal/sdkv2provider/resource_cloudflare_waiting_room_test.go
index 248e1fdc32..2f66d939ed 100644
--- a/internal/sdkv2provider/resource_cloudflare_waiting_room_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_waiting_room_test.go
@@ -108,7 +108,7 @@ func testAccCloudflareWaitingRoom(resourceName, waitingRoomName, zoneID, domain,
resource "cloudflare_record" "%[1]s-shop-1" {
zone_id = "%[3]s"
name = "shop1"
- value = "192.168.0.10"
+ content = "192.168.0.10"
type = "A"
ttl = 3600
}
@@ -116,7 +116,7 @@ func testAccCloudflareWaitingRoom(resourceName, waitingRoomName, zoneID, domain,
resource "cloudflare_record" "%[1]s-shop-2" {
zone_id = "%[3]s"
name = "shop2"
- value = "192.168.0.11"
+ content = "192.168.0.11"
type = "A"
ttl = 3600
}
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger.go b/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger.go
index e5e1baf576..5b5fe4a112 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger.go
@@ -32,6 +32,26 @@ func resourceCloudflareWorkerCronTrigger() *schema.Resource {
}
}
+func resourceCloudflareWorkersCronTrigger() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareWorkerCronTriggerSchema(),
+ CreateContext: resourceCloudflareWorkerCronTriggerUpdate,
+ ReadContext: resourceCloudflareWorkerCronTriggerRead,
+ UpdateContext: resourceCloudflareWorkerCronTriggerUpdate,
+ DeleteContext: resourceCloudflareWorkerCronTriggerDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareWorkerCronTriggerImport,
+ },
+ Description: heredoc.Doc(fmt.Sprintf(`
+ Worker Cron Triggers allow users to map a cron expression to a Worker script
+ using a %s listener that enables Workers to be executed on a
+ schedule. Worker Cron Triggers are ideal for running periodic jobs for
+ maintenance or calling third-party APIs to collect up-to-date data.
+ `, "`ScheduledEvent`")),
+ DeprecationMessage: "`cloudflare_worker_cron_trigger` is now deprecated and will be removed in the next major version. Use `cloudflare_workers_cron_trigger` instead.",
+ }
+}
+
// resourceCloudflareWorkerCronTriggerUpdate is used for creation and updates of
// Worker Cron Triggers as the remote API endpoint is shared uses HTTP PUT.
func resourceCloudflareWorkerCronTriggerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger_test.go b/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger_test.go
index 12ef25b30d..4272deb469 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_cron_trigger_test.go
@@ -10,7 +10,7 @@ import (
func TestAccCloudflareWorkerCronTrigger_Basic(t *testing.T) {
rnd := generateRandomResourceName()
- name := fmt.Sprintf("cloudflare_worker_cron_trigger.%s", rnd)
+ name := fmt.Sprintf("cloudflare_workers_cron_trigger.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -32,15 +32,15 @@ func TestAccCloudflareWorkerCronTrigger_Basic(t *testing.T) {
func testAccCloudflareWorkerCronTriggerConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_script" "%[1]s" {
+resource "cloudflare_workers_script" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
content = "addEventListener('fetch', event => {event.respondWith(new Response('test'))});"
}
-resource "cloudflare_worker_cron_trigger" "%[1]s" {
+resource "cloudflare_workers_cron_trigger" "%[1]s" {
account_id = "%[2]s"
- script_name = cloudflare_worker_script.%[1]s.name
+ script_name = cloudflare_workers_script.%[1]s.name
schedules = [
"*/5 * * * *", # every 5 minutes
"10 7 * * mon-fri", # 7:10am every weekday
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_domain.go b/internal/sdkv2provider/resource_cloudflare_workers_domain.go
index f2d0e339e9..661acfdef9 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_domain.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_domain.go
@@ -14,6 +14,23 @@ import (
)
func resourceCloudflareWorkerDomain() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareWorkerDomainSchema(),
+ CreateContext: resourceCloudflareWorkerDomainCreate,
+ ReadContext: resourceCloudflareWorkerDomainRead,
+ UpdateContext: resourceCloudflareWorkerDomainUpdate,
+ DeleteContext: resourceCloudflareWorkerDomainDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareWorkerDomainImport,
+ },
+ Description: heredoc.Doc(
+ "Creates a Worker Custom Domain.",
+ ),
+ DeprecationMessage: "`cloudflare_worker_domain` is now deprecated and will be removed in the next major version. Use `cloudflare_workers_domain` instead.",
+ }
+}
+
+func resourceCloudflareWorkersDomain() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareWorkerDomainSchema(),
CreateContext: resourceCloudflareWorkerDomainCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_domain_test.go b/internal/sdkv2provider/resource_cloudflare_workers_domain_test.go
index fbd81b0bc4..40fb24eba2 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_domain_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_domain_test.go
@@ -20,7 +20,7 @@ func TestAccCloudflareWorkerDomain_Attach(t *testing.T) {
zoneName := os.Getenv("CLOUDFLARE_DOMAIN")
var domain cloudflare.WorkersDomain
rnd := generateRandomResourceName()
- name := "cloudflare_worker_domain." + rnd
+ name := "cloudflare_workers_domain." + rnd
hostname := rnd + "." + zoneName
resource.Test(t, resource.TestCase{
@@ -96,18 +96,18 @@ func testAccCheckCloudflareWorkerDomainExists(resourceName string, domain *cloud
func testAccCheckCloudflareWorkerDomainAttach(rnd, accountID string, hostname string, zoneID string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_script" "%[1]s-script" {
+resource "cloudflare_workers_script" "%[1]s-script" {
account_id = "%[3]s"
name = "%[1]s"
content = "%[2]s"
}
-resource "cloudflare_worker_domain" "%[1]s" {
+resource "cloudflare_workers_domain" "%[1]s" {
zone_id = "%[5]s"
account_id = "%[3]s"
hostname = "%[4]s"
service = "%[1]s"
- depends_on = [cloudflare_worker_script.%[1]s-script]
+ depends_on = [cloudflare_workers_script.%[1]s-script]
}`, rnd, scriptContent, accountID, hostname, zoneID)
}
@@ -115,7 +115,7 @@ func testAccCheckCloudflareWorkerDomainDestroy(s *terraform.State) error {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_worker_domain" {
+ if rs.Type != "cloudflare_workers_domain" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_route.go b/internal/sdkv2provider/resource_cloudflare_workers_route.go
index b4ab33800b..8b9612dcab 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_route.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_route.go
@@ -16,6 +16,21 @@ import (
)
func resourceCloudflareWorkerRoute() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareWorkerRouteSchema(),
+ CreateContext: resourceCloudflareWorkerRouteCreate,
+ ReadContext: resourceCloudflareWorkerRouteRead,
+ UpdateContext: resourceCloudflareWorkerRouteUpdate,
+ DeleteContext: resourceCloudflareWorkerRouteDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareWorkerRouteImport,
+ },
+ Description: heredoc.Doc("Provides a Cloudflare worker route resource. A route will also require a `cloudflare_worker_script`."),
+ DeprecationMessage: "`cloudflare_worker_route` is now deprecated and will be removed in the next major version. Use `cloudflare_workers_route` instead.",
+ }
+}
+
+func resourceCloudflareWorkersRoute() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareWorkerRouteSchema(),
CreateContext: resourceCloudflareWorkerRouteCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_route_test.go b/internal/sdkv2provider/resource_cloudflare_workers_route_test.go
index bd35a8130b..969e7cfb44 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_route_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_route_test.go
@@ -29,7 +29,7 @@ func TestAccCloudflareWorkerRoute_MultiScript(t *testing.T) {
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
routeRnd := generateRandomResourceName()
- routeName := "cloudflare_worker_route." + routeRnd
+ routeName := "cloudflare_workers_route." + routeRnd
pattern1 := fmt.Sprintf("%s/%s", zoneName, generateRandomResourceName())
pattern2 := fmt.Sprintf("%s/%s", zoneName, generateRandomResourceName())
@@ -69,13 +69,13 @@ func TestAccCloudflareWorkerRoute_MultiScript(t *testing.T) {
func testAccCheckCloudflareWorkerRouteConfigMultiScriptInitial(zoneID, accountID, routeRnd, scriptRnd, pattern string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_route" "%[3]s" {
+resource "cloudflare_workers_route" "%[3]s" {
zone_id = "%[1]s"
pattern = "%[5]s"
- script_name = "${cloudflare_worker_script.%[4]s.name}"
+ script_name = "${cloudflare_workers_script.%[4]s.name}"
}
-resource "cloudflare_worker_script" "%[4]s" {
+resource "cloudflare_workers_script" "%[4]s" {
account_id = "%[2]s"
name = "%[4]s"
content = "%[6]s"
@@ -84,12 +84,12 @@ resource "cloudflare_worker_script" "%[4]s" {
func testAccCheckCloudflareWorkerRouteConfigMultiScriptUpdate(zoneID, accountID, routeRnd, scriptRnd, pattern string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_route" "%[3]s" {
+resource "cloudflare_workers_route" "%[3]s" {
zone_id = "%[1]s"
pattern = "%[5]s"
}
-resource "cloudflare_worker_script" "%[4]s" {
+resource "cloudflare_workers_script" "%[4]s" {
account_id = "%[2]s"
name = "%[4]s"
content = "%[6]s"
@@ -108,7 +108,7 @@ func TestAccCloudflareWorkerRoute_MultiScriptDisabledRoute(t *testing.T) {
zoneName := os.Getenv("CLOUDFLARE_DOMAIN")
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
routeRnd := generateRandomResourceName()
- routeName := "cloudflare_worker_route." + routeRnd
+ routeName := "cloudflare_workers_route." + routeRnd
pattern := fmt.Sprintf("%s/%s", zoneName, generateRandomResourceName())
resource.Test(t, resource.TestCase{
@@ -134,7 +134,7 @@ func TestAccCloudflareWorkerRoute_MultiScriptDisabledRoute(t *testing.T) {
func testAccCheckCloudflareWorkerRouteConfigMultiScriptDisabledRoute(zoneID, routeRnd, pattern string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_route" "%[2]s" {
+resource "cloudflare_workers_route" "%[2]s" {
zone_id = "%[1]s"
pattern = "%[3]s"
}`, zoneID, routeRnd, pattern)
@@ -194,7 +194,7 @@ func testAccCheckCloudflareWorkerRouteExists(n string, route *cloudflare.WorkerR
func testAccCheckCloudflareWorkerRouteDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_worker_route" {
+ if rs.Type != "cloudflare_workers_route" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_script.go b/internal/sdkv2provider/resource_cloudflare_workers_script.go
index ab4358e86f..d511097a34 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_script.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_script.go
@@ -17,6 +17,23 @@ import (
)
func resourceCloudflareWorkerScript() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareWorkerScriptSchema(),
+ CreateContext: resourceCloudflareWorkerScriptCreate,
+ ReadContext: resourceCloudflareWorkerScriptRead,
+ UpdateContext: resourceCloudflareWorkerScriptUpdate,
+ DeleteContext: resourceCloudflareWorkerScriptDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareWorkerScriptImport,
+ },
+ Description: heredoc.Doc(
+ "Provides a Cloudflare worker script resource. In order for a script to be active, you'll also need to setup a `cloudflare_worker_route`.",
+ ),
+ DeprecationMessage: "`cloudflare_worker_script` is now deprecated and will be removed in the next major version. Use `cloudflare_workers_script` instead.",
+ }
+}
+
+func resourceCloudflareWorkersScript() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareWorkerScriptSchema(),
CreateContext: resourceCloudflareWorkerScriptCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_script_test.go b/internal/sdkv2provider/resource_cloudflare_workers_script_test.go
index 3b822a5b88..c413d6d3b3 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_script_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_script_test.go
@@ -34,7 +34,7 @@ func TestAccCloudflareWorkerScript_MultiScriptEnt(t *testing.T) {
var script cloudflare.WorkerScript
rnd := generateRandomResourceName()
- name := "cloudflare_worker_script." + rnd
+ name := "cloudflare_workers_script." + rnd
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
resource.Test(t, resource.TestCase{
@@ -79,7 +79,7 @@ func TestAccCloudflareWorkerScript_ModuleUpload(t *testing.T) {
var script cloudflare.WorkerScript
rnd := generateRandomResourceName()
- name := "cloudflare_worker_script." + rnd
+ name := "cloudflare_workers_script." + rnd
r2AccesKeyID := os.Getenv("CLOUDFLARE_R2_ACCESS_KEY_ID")
r2AccesKeySecret := os.Getenv("CLOUDFLARE_R2_ACCESS_KEY_SECRET")
@@ -173,7 +173,7 @@ func testAccCheckCloudflareWorkerScriptCreateBucket(t *testing.T, rnd string) {
func testAccCheckCloudflareWorkerScriptConfigMultiScriptInitial(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_script" "%[1]s" {
+resource "cloudflare_workers_script" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
content = "%[2]s"
@@ -182,7 +182,7 @@ resource "cloudflare_worker_script" "%[1]s" {
func testAccCheckCloudflareWorkerScriptConfigMultiScriptUpdate(rnd, accountID string) string {
return fmt.Sprintf(`
-resource "cloudflare_worker_script" "%[1]s" {
+resource "cloudflare_workers_script" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
content = "%[2]s"
@@ -201,13 +201,13 @@ resource "cloudflare_queue" "%[1]s" {
name = "%[1]s"
}
-resource "cloudflare_worker_script" "%[1]s-service" {
+resource "cloudflare_workers_script" "%[1]s-service" {
account_id = "%[4]s"
name = "%[1]s-service"
content = "%[2]s"
}
-resource "cloudflare_worker_script" "%[1]s" {
+resource "cloudflare_workers_script" "%[1]s" {
account_id = "%[4]s"
name = "%[1]s"
content = "%[2]s"
@@ -239,7 +239,7 @@ resource "cloudflare_worker_script" "%[1]s" {
service_binding {
name = "MY_SERVICE_BINDING"
- service = cloudflare_worker_script.%[1]s-service.name
+ service = cloudflare_workers_script.%[1]s-service.name
environment = "production"
}
@@ -262,7 +262,7 @@ func testAccCheckCloudflareWorkerScriptUploadModule(rnd, accountID, r2AccessKeyI
dataset = "workers_trace_events"
}
-resource "cloudflare_worker_script" "%[1]s" {
+resource "cloudflare_workers_script" "%[1]s" {
account_id = "%[3]s"
name = "%[1]s"
content = "%[2]s"
@@ -307,7 +307,7 @@ func testAccCheckCloudflareWorkerScriptExists(n string, script *cloudflare.Worke
return fmt.Errorf("Worker Script not found")
}
- name := strings.Replace(n, "cloudflare_worker_script.", "", -1)
+ name := strings.Replace(n, "cloudflare_workers_script.", "", -1)
foundBindings, err := getWorkerScriptBindings(context.Background(), accountID, name, nil, client)
if err != nil {
return fmt.Errorf("cannot list script bindings: %w", err)
@@ -328,7 +328,7 @@ func testAccCheckCloudflareWorkerScriptDestroy(s *terraform.State) error {
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_worker_script" {
+ if rs.Type != "cloudflare_workers_script" {
continue
}
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_secret.go b/internal/sdkv2provider/resource_cloudflare_workers_secret.go
index 7128b55ca7..725d4bc9dd 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_secret.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_secret.go
@@ -15,6 +15,21 @@ import (
)
func resourceCloudflareWorkerSecret() *schema.Resource {
+ return &schema.Resource{
+ Schema: resourceCloudflareWorkerSecretSchema(),
+ CreateContext: resourceCloudflareWorkerSecretCreate,
+ ReadContext: resourceCloudflareWorkerSecretRead,
+ UpdateContext: resourceCloudflareWorkerSecretCreate,
+ DeleteContext: resourceCloudflareWorkerSecretDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceCloudflareWorkerSecretImport,
+ },
+ Description: heredoc.Doc("Provides a Cloudflare Worker secret resource."),
+ DeprecationMessage: "`cloudflare_worker_secret` is now deprecated and will be removed in the next major version. Use `cloudflare_workers_secret` instead.",
+ }
+}
+
+func resourceCloudflareWorkersSecret() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareWorkerSecretSchema(),
CreateContext: resourceCloudflareWorkerSecretCreate,
diff --git a/internal/sdkv2provider/resource_cloudflare_workers_secret_test.go b/internal/sdkv2provider/resource_cloudflare_workers_secret_test.go
index e5a19a7f61..2f7f7b0ad6 100644
--- a/internal/sdkv2provider/resource_cloudflare_workers_secret_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_workers_secret_test.go
@@ -39,7 +39,7 @@ func TestAccCloudflareWorkerSecret_Basic(t *testing.T) {
},
{
Config: testAccCheckCloudflareWorkerSecretWithWorkerScript(workerSecretTestScriptName, name, secretText, accountId),
- ResourceName: "cloudflare_worker_secret." + name,
+ ResourceName: "cloudflare_workers_secret." + name,
ImportStateId: fmt.Sprintf("%s/%s/%s", accountID, workerSecretTestScriptName, name),
ImportState: true,
ImportStateVerify: true,
@@ -56,7 +56,7 @@ func testAccCheckCloudflareWorkerSecretDestroy(s *terraform.State) error {
accountId := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
for _, rs := range s.RootModule().Resources {
- if rs.Type != "cloudflare_worker_secret" {
+ if rs.Type != "cloudflare_workers_secret" {
continue
}
@@ -77,15 +77,15 @@ func testAccCheckCloudflareWorkerSecretDestroy(s *terraform.State) error {
func testAccCheckCloudflareWorkerSecretWithWorkerScript(scriptName string, name string, secretText string, accountId string) string {
return fmt.Sprintf(`
- resource "cloudflare_worker_script" "%[2]s" {
+ resource "cloudflare_workers_script" "%[2]s" {
account_id = "%[4]s"
name = "%[1]s"
content = "%[5]s"
}
- resource "cloudflare_worker_secret" "%[2]s" {
+ resource "cloudflare_workers_secret" "%[2]s" {
account_id = "%[4]s"
- script_name = cloudflare_worker_script.%[2]s.name
+ script_name = cloudflare_workers_script.%[2]s.name
name = "%[2]s"
secret_text = "%[3]s"
}`, scriptName, name, secretText, accountId, scriptContentForSecret)
diff --git a/internal/sdkv2provider/resource_cloudflare_zone_settings_override.go b/internal/sdkv2provider/resource_cloudflare_zone_settings_override.go
index a7b3f9ea9d..0aa6321cfa 100644
--- a/internal/sdkv2provider/resource_cloudflare_zone_settings_override.go
+++ b/internal/sdkv2provider/resource_cloudflare_zone_settings_override.go
@@ -19,12 +19,25 @@ import (
func resourceCloudflareZoneSettingsOverride() *schema.Resource {
return &schema.Resource{
+ SchemaVersion: 2,
Schema: resourceCloudflareZoneSettingsOverrideSchema(),
CreateContext: resourceCloudflareZoneSettingsOverrideCreate,
ReadContext: resourceCloudflareZoneSettingsOverrideRead,
UpdateContext: resourceCloudflareZoneSettingsOverrideUpdate,
DeleteContext: resourceCloudflareZoneSettingsOverrideDelete,
Description: "Provides a resource which customizes Cloudflare zone settings.",
+ StateUpgraders: []schema.StateUpgrader{
+ {
+ Version: 0,
+ Type: resourceCloudflareZoneSettingsOverrideV0().CoreConfigSchema().ImpliedType(),
+ Upgrade: resourceCloudflareZoneSettingsOverrideStateUpgradeV1,
+ },
+ {
+ Version: 1,
+ Type: resourceCloudflareZoneSettingsOverrideV1().CoreConfigSchema().ImpliedType(),
+ Upgrade: resourceCloudflareZoneSettingsOverrideStateUpgradeV2,
+ },
+ },
}
}
@@ -187,7 +200,7 @@ func flattenZoneSettings(ctx context.Context, d *schema.ResourceData, settings [
continue
}
- if s.ID == "minify" || s.ID == "mobile_redirect" || s.ID == "nel" {
+ if s.ID == "nel" {
cfg[s.ID] = []interface{}{s.Value.(map[string]interface{})}
} else if s.ID == "security_header" {
cfg[s.ID] = []interface{}{s.Value.(map[string]interface{})["strict_transport_security"]}
@@ -355,7 +368,7 @@ func expandZoneSetting(d *schema.ResourceData, keyFormatString, k string, settin
zoneSettingValue = settingValue
}
}
- case "minify", "mobile_redirect", "nel":
+ case "nel":
{
listValue := settingValue.([]interface{})
if len(listValue) > 0 && listValue != nil {
diff --git a/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go
new file mode 100644
index 0000000000..fa71186a8b
--- /dev/null
+++ b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go
@@ -0,0 +1,100 @@
+package sdkv2provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceCloudflareZoneSettingsOverrideV0() *schema.Resource {
+ return &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "settings": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: resourceCloudflareZoneSettingsSchemaV0,
+ },
+ },
+
+ "initial_settings": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: resourceCloudflareZoneSettingsSchemaV0,
+ },
+ },
+ },
+ }
+}
+
+func resourceCloudflareZoneSettingsOverrideStateUpgradeV1(
+ _ context.Context,
+ rawState map[string]interface{},
+ _ interface{},
+) (map[string]interface{}, error) {
+ errMsg := "could not upgrade cloudflare_zone_settings_override from v0 to v1"
+
+ if rawState == nil {
+ return nil, fmt.Errorf("%s: state is nil", errMsg)
+ }
+
+ upgrade := func(state map[string]interface{}, name string) map[string]interface{} {
+ delete(state[name].([]interface{})[0].(map[string]interface{}), "mobile_redirect")
+ return state
+ }
+
+ state := upgrade(rawState, "settings")
+ state = upgrade(state, "initial_settings")
+
+ return state, nil
+}
+
+func resourceCloudflareZoneSettingsOverrideV1() *schema.Resource {
+ return &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "settings": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: resourceCloudflareZoneSettingsSchemaV1,
+ },
+ },
+
+ "initial_settings": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: resourceCloudflareZoneSettingsSchemaV1,
+ },
+ },
+ },
+ }
+}
+
+func resourceCloudflareZoneSettingsOverrideStateUpgradeV2(
+ _ context.Context,
+ rawState map[string]interface{},
+ _ interface{},
+) (map[string]interface{}, error) {
+ errMsg := "could not upgrade cloudflare_zone_settings_override from v1 to v2"
+
+ if rawState == nil {
+ return nil, fmt.Errorf("%s: state is nil", errMsg)
+ }
+
+ upgrade := func(state map[string]interface{}, name string) map[string]interface{} {
+ delete(state[name].([]interface{})[0].(map[string]interface{}), "minify")
+ return state
+ }
+
+ state := upgrade(rawState, "settings")
+ state = upgrade(state, "initial_settings")
+
+ return state, nil
+}
diff --git a/internal/sdkv2provider/resource_cloudflare_zone_settings_override_test.go b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_test.go
index 1635380488..fb3f0e2c8f 100644
--- a/internal/sdkv2provider/resource_cloudflare_zone_settings_override_test.go
+++ b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_test.go
@@ -6,6 +6,8 @@ import (
"os"
"testing"
+ "github.com/stretchr/testify/require"
+
"reflect"
cloudflare "github.com/cloudflare/cloudflare-go"
@@ -206,11 +208,6 @@ resource "cloudflare_zone_settings_override" "%[1]s" {
fonts = "on"
origin_max_http_version = "2"
universal_ssl = "off"
- minify {
- css = "on"
- js = "off"
- html = "off"
- }
security_header {
enabled = true
}
@@ -250,3 +247,73 @@ resource "cloudflare_zone_settings_override" "%[1]s" {
}
}`, rnd, zoneID)
}
+
+func TestCloudflareZoneSettingsOverrideStateUpgradeV0(t *testing.T) {
+ v0 := map[string]interface{}{
+ "settings": []interface{}{map[string]interface{}{
+ "mobile_redirect": map[string]interface{}{
+ "mobile_subdomain": "",
+ "status": "",
+ "strip_uri": true,
+ },
+ "other_thing": "foo",
+ }},
+ "initial_settings": []interface{}{map[string]interface{}{
+ "mobile_redirect": map[string]interface{}{
+ "mobile_subdomain": "",
+ "status": "",
+ "strip_uri": true,
+ },
+ "other_thing": "foo",
+ }},
+ }
+
+ expectedV1 := map[string]interface{}{
+ "settings": []interface{}{map[string]interface{}{
+ "other_thing": "foo",
+ }},
+ "initial_settings": []interface{}{map[string]interface{}{
+ "other_thing": "foo",
+ }},
+ }
+
+ actualV1, err := resourceCloudflareZoneSettingsOverrideStateUpgradeV1(context.Background(), v0, nil)
+ require.NoError(t, err)
+
+ require.Equal(t, expectedV1, actualV1)
+}
+
+func TestCloudflareZoneSettingsOverrideStateUpgradeV1(t *testing.T) {
+ v1 := map[string]interface{}{
+ "settings": []interface{}{map[string]interface{}{
+ "minify": map[string]interface{}{
+ "css": "on",
+ "js": "on",
+ "html": "off",
+ },
+ "other_thing": "foo",
+ }},
+ "initial_settings": []interface{}{map[string]interface{}{
+ "minify": map[string]interface{}{
+ "css": "on",
+ "js": "on",
+ "html": "off",
+ },
+ "other_thing": "foo",
+ }},
+ }
+
+ expectedV2 := map[string]interface{}{
+ "settings": []interface{}{map[string]interface{}{
+ "other_thing": "foo",
+ }},
+ "initial_settings": []interface{}{map[string]interface{}{
+ "other_thing": "foo",
+ }},
+ }
+
+ actualV2, err := resourceCloudflareZoneSettingsOverrideStateUpgradeV2(context.Background(), v1, nil)
+ require.NoError(t, err)
+
+ require.Equal(t, expectedV2, actualV2)
+}
diff --git a/internal/sdkv2provider/schema_cloudflare_access_application.go b/internal/sdkv2provider/schema_cloudflare_access_application.go
index 188694102e..db049d123f 100644
--- a/internal/sdkv2provider/schema_cloudflare_access_application.go
+++ b/internal/sdkv2provider/schema_cloudflare_access_application.go
@@ -67,7 +67,6 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
},
Optional: true,
Description: "The policies associated with the application, in ascending order of precedence." +
- " When omitted, the application policies are not be updated." +
" Warning: Do not use this field while you still have this application ID referenced as `application_id`" +
" in any `cloudflare_access_policy` resource, as it can result in an inconsistent state.",
},
@@ -223,6 +222,11 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
Optional: true,
Description: "A regex to filter Cloudflare groups returned in ID token and userinfo endpoint",
},
+ "access_token_lifetime": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "The lifetime of the Access Token after creation. Valid units are `m` and `h`. Must be greater than or equal to 1m and less than or equal to 24h.",
+ },
"allow_pkce_without_client_secret": {
Type: schema.TypeBool,
Optional: true,
@@ -237,7 +241,7 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
"lifetime": {
Type: schema.TypeString,
Optional: true,
- Description: "How long a refresh token will be valid for after creation. Valid units are m,h,d. Must be longer than 1m.",
+ Description: "How long a refresh token will be valid for after creation. Valid units are `m`, `h` and `d`. Must be longer than 1m.",
},
},
},
@@ -555,6 +559,12 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
},
},
},
+ "skip_app_launcher_login_page": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ Description: "Option to skip the App Launcher landing page.",
+ },
"allow_authenticate_via_warp": {
Type: schema.TypeBool,
Optional: true,
@@ -875,6 +885,7 @@ func convertSaasSchemaToStruct(d *schema.ResourceData) *cloudflare.SaasApplicati
SaasConfig.GrantTypes = expandInterfaceToStringList(d.Get("saas_app.0.grant_types").(*schema.Set).List())
SaasConfig.Scopes = expandInterfaceToStringList(d.Get("saas_app.0.scopes").(*schema.Set).List())
SaasConfig.GroupFilterRegex = d.Get("saas_app.0.group_filter_regex").(string)
+ SaasConfig.AccessTokenLifetime = d.Get("saas_app.0.access_token_lifetime").(string)
SaasConfig.AllowPKCEWithoutClientSecret = cloudflare.BoolPtr(d.Get("saas_app.0.allow_pkce_without_client_secret").(bool))
if _, ok := d.GetOk("saas_app.0.refresh_token_options"); ok {
SaasConfig.RefreshTokenOptions = &cloudflare.RefreshTokenOptions{
@@ -1158,6 +1169,7 @@ func convertSaasStructToSchema(d *schema.ResourceData, app *cloudflare.SaasAppli
"scopes": app.Scopes,
"public_key": app.PublicKey,
"group_filter_regex": app.GroupFilterRegex,
+ "access_token_lifetime": app.AccessTokenLifetime,
"app_launcher_url": app.AppLauncherURL,
"allow_pkce_without_client_secret": app.AllowPKCEWithoutClientSecret,
}
diff --git a/internal/sdkv2provider/schema_cloudflare_access_policy.go b/internal/sdkv2provider/schema_cloudflare_access_policy.go
index c8498482f6..3a99d9279b 100644
--- a/internal/sdkv2provider/schema_cloudflare_access_policy.go
+++ b/internal/sdkv2provider/schema_cloudflare_access_policy.go
@@ -16,10 +16,7 @@ func resourceCloudflareAccessPolicySchema() map[string]*schema.Schema {
Optional: true,
ForceNew: true,
RequiredWith: []string{"precedence"},
- Deprecated: "This field is deprecated. Policies can now be standalone and reusable by multiple applications." +
- "Please use `cloudflare_access_application.policies` to associate reusable access policies with access" +
- " applications.",
- Description: "The ID of the application the policy is associated with.",
+ Description: "The ID of the application the policy is associated with.",
},
consts.AccountIDSchemaKey: {
Description: consts.AccountIDSchemaDescription,
@@ -42,10 +39,7 @@ func resourceCloudflareAccessPolicySchema() map[string]*schema.Schema {
Type: schema.TypeInt,
Optional: true,
RequiredWith: []string{"application_id"},
- Deprecated: "This field is deprecated. Access policies can now be reusable by multiple applications." +
- " Please use `cloudflare_access_application.policies` to link policies to an application with" +
- " ascending order of precedence.",
- Description: "The unique precedence for policies on a single application.",
+ Description: "The unique precedence for policies on a single application.",
},
"decision": {
Type: schema.TypeString,
diff --git a/internal/sdkv2provider/schema_cloudflare_device_posture_rule.go b/internal/sdkv2provider/schema_cloudflare_device_posture_rule.go
index 098a4c300c..f14e7d0a1b 100644
--- a/internal/sdkv2provider/schema_cloudflare_device_posture_rule.go
+++ b/internal/sdkv2provider/schema_cloudflare_device_posture_rule.go
@@ -9,7 +9,7 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
)
-var devicePostureRuleTypes = []string{"serial_number", "file", "application", "gateway", "warp", "domain_joined", "os_version", "disk_encryption", "firewall", "client_certificate", "workspace_one", "unique_client_id", "crowdstrike_s2s", "sentinelone", "kolide", "tanium_s2s", "intune", "sentinelone_s2s"}
+var devicePostureRuleTypes = []string{"serial_number", "file", "application", "gateway", "warp", "domain_joined", "os_version", "disk_encryption", "firewall", "client_certificate", "client_certificate_v2", "workspace_one", "unique_client_id", "crowdstrike_s2s", "sentinelone", "kolide", "tanium_s2s", "intune", "sentinelone_s2s"}
func resourceCloudflareDevicePostureRuleSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
@@ -141,13 +141,13 @@ func resourceCloudflareDevicePostureRuleSchema() map[string]*schema.Schema {
"connection_id": {
Type: schema.TypeString,
Optional: true,
- Description: "The workspace one connection id.",
+ Description: "The workspace one or intune connection id.",
},
"compliance_status": {
Type: schema.TypeString,
Optional: true,
- ValidateFunc: validation.StringInSlice([]string{"compliant", "noncompliant"}, true),
- Description: fmt.Sprintf("The workspace one device compliance status. %s", renderAvailableDocumentationValuesStringSlice([]string{"compliant", "noncompliant"})),
+ ValidateFunc: validation.StringInSlice([]string{"compliant", "noncompliant", "unknown", "conflict", "error", "ingraceperiod"}, true),
+ Description: fmt.Sprintf("The workspace one or intune device compliance status. `compliant` and `noncompliant` are values supported by both providers. `unknown`, `conflict`, `error`, `ingraceperiod` values are only supported by intune. %s", renderAvailableDocumentationValuesStringSlice([]string{"compliant", "noncompliant", "unknown", "conflict", "error", "ingraceperiod"})),
},
"os_distro_name": {
Type: schema.TypeString,
@@ -238,7 +238,7 @@ func resourceCloudflareDevicePostureRuleSchema() map[string]*schema.Schema {
"eid_last_seen": {
Type: schema.TypeString,
Optional: true,
- Description: "The datetime a device last seen in RFC 3339 format from Tanium.",
+ Description: "The time a device last seen in Tanium. Must be in the format `1h` or `30m`. Valid units are `d`, `h` and `m`",
},
"risk_level": {
Type: schema.TypeString,
@@ -251,6 +251,44 @@ func resourceCloudflareDevicePostureRuleSchema() map[string]*schema.Schema {
Optional: true,
Description: "The total score from Tanium.",
},
+ "check_private_key": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Confirm the certificate was not imported from another device.",
+ },
+ "extended_key_usage": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: fmt.Sprintf("List of values indicating purposes for which the certificate public key can be used. %s", renderAvailableDocumentationValuesStringSlice([]string{"clientAuth", "emailProtection"})),
+ },
+ "locations": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "paths": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of paths to check for client certificate rule.",
+ },
+ "trust_stores": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: fmt.Sprintf("List of trust stores to check for client certificate rule. %s", renderAvailableDocumentationValuesStringSlice([]string{"system", "user"})),
+ },
+ },
+ },
+ Optional: true,
+ Description: "List of locations to check for client certificate.",
+ },
},
},
},
diff --git a/internal/sdkv2provider/schema_cloudflare_device_settings_policy.go b/internal/sdkv2provider/schema_cloudflare_device_settings_policy.go
index 33809299f3..31d2590f98 100644
--- a/internal/sdkv2provider/schema_cloudflare_device_settings_policy.go
+++ b/internal/sdkv2provider/schema_cloudflare_device_settings_policy.go
@@ -106,5 +106,12 @@ func resourceCloudflareDeviceSettingsPolicySchema() map[string]*schema.Schema {
Type: schema.TypeBool,
Optional: true,
},
+ "tunnel_protocol": {
+ Description: fmt.Sprintf("Determines which tunnel protocol to use. %s", renderAvailableDocumentationValuesStringSlice([]string{"", "wireguard", "masque"})),
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.StringInSlice([]string{"", "wireguard", "masque"}, false),
+ Default: "wireguard",
+ },
}
}
diff --git a/internal/sdkv2provider/schema_cloudflare_logpush_job.go b/internal/sdkv2provider/schema_cloudflare_logpush_job.go
index 358377e133..aa006f1f0d 100644
--- a/internal/sdkv2provider/schema_cloudflare_logpush_job.go
+++ b/internal/sdkv2provider/schema_cloudflare_logpush_job.go
@@ -97,6 +97,7 @@ func resourceCloudflareLogpushJobSchema() map[string]*schema.Schema {
Optional: true,
Default: "high",
ValidateFunc: validation.StringInSlice(frequencyAllowedValues, false),
+ Deprecated: "`frequency` has been deprecated in favour of using `max_upload_interval_seconds` instead.",
Description: fmt.Sprintf("A higher frequency will result in logs being pushed on faster with smaller files. `low` frequency will push logs less often with larger files. %s", renderAvailableDocumentationValuesStringSlice(frequencyAllowedValues)),
},
"max_upload_bytes": {
diff --git a/internal/sdkv2provider/schema_cloudflare_notification_policy.go b/internal/sdkv2provider/schema_cloudflare_notification_policy.go
index 40f1fb345f..f214f5a361 100644
--- a/internal/sdkv2provider/schema_cloudflare_notification_policy.go
+++ b/internal/sdkv2provider/schema_cloudflare_notification_policy.go
@@ -514,6 +514,14 @@ func notificationPolicyFilterSchema() *schema.Schema {
Optional: true,
Description: "Tunnel IDs to alert on.",
},
+ "tunnel_name": {
+ Type: schema.TypeSet,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Optional: true,
+ Description: "Tunnel Names to alert on.",
+ },
},
},
}
diff --git a/internal/sdkv2provider/schema_cloudflare_notification_policy_webhooks.go b/internal/sdkv2provider/schema_cloudflare_notification_policy_webhooks.go
index fab62250f0..e7afdec1f4 100644
--- a/internal/sdkv2provider/schema_cloudflare_notification_policy_webhooks.go
+++ b/internal/sdkv2provider/schema_cloudflare_notification_policy_webhooks.go
@@ -45,7 +45,7 @@ func resourceCloudflareNotificationPolicyWebhookSchema() map[string]*schema.Sche
"last_failure": {
Type: schema.TypeString,
Computed: true,
- Description: "Timestamp of when the notification webhook last faiuled.",
+ Description: "Timestamp of when the notification webhook last failed.",
},
}
}
diff --git a/internal/sdkv2provider/schema_cloudflare_record.go b/internal/sdkv2provider/schema_cloudflare_record.go
index 90dd07259f..40fbc8eb8a 100644
--- a/internal/sdkv2provider/schema_cloudflare_record.go
+++ b/internal/sdkv2provider/schema_cloudflare_record.go
@@ -47,17 +47,27 @@ func resourceCloudflareRecordSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
Computed: true,
- ConflictsWith: []string{"data"},
+ ExactlyOneOf: []string{"data", "content", "value"},
DiffSuppressFunc: suppressTrailingDots,
Description: "The value of the record.",
+ Deprecated: "`value` is deprecated in favour of `content` and will be removed in the next major release.",
+ },
+
+ "content": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ExactlyOneOf: []string{"data", "content", "value"},
+ DiffSuppressFunc: suppressTrailingDots,
+ Description: "The content of the record.",
},
"data": {
- Type: schema.TypeList,
- MaxItems: 1,
- Optional: true,
- ConflictsWith: []string{"value"},
- Description: "Map of attributes that constitute the record value.",
+ Type: schema.TypeList,
+ MaxItems: 1,
+ Optional: true,
+ ExactlyOneOf: []string{"data", "content", "value"},
+ Description: "Map of attributes that constitute the record value.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
// Properties present in several record types
diff --git a/internal/sdkv2provider/schema_cloudflare_teams_list.go b/internal/sdkv2provider/schema_cloudflare_teams_list.go
index 5f9ec24296..fbdbc64fc3 100644
--- a/internal/sdkv2provider/schema_cloudflare_teams_list.go
+++ b/internal/sdkv2provider/schema_cloudflare_teams_list.go
@@ -34,10 +34,34 @@ func resourceCloudflareTeamsListSchema() map[string]*schema.Schema {
"items": {
Type: schema.TypeSet,
Optional: true,
+ MaxItems: 30000,
Description: "The items of the teams list.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
+ // Adding items with description as optional separate field, so they
+ // do not drown in between 1000s of string values at items attribute.
+ // Use this field only if you have descriptions. The provider joins
+ // items without description and this field together before processing.
+ "items_with_description": {
+ Type: schema.TypeSet,
+ Optional: true,
+ MaxItems: 30000,
+ Description: "The items of the teams list that has explicit description.",
+ ConfigMode: schema.SchemaConfigModeAttr,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ },
+ },
+ },
}
}
diff --git a/internal/sdkv2provider/schema_cloudflare_teams_rules.go b/internal/sdkv2provider/schema_cloudflare_teams_rules.go
index 14ac3820a5..343d1c108b 100644
--- a/internal/sdkv2provider/schema_cloudflare_teams_rules.go
+++ b/internal/sdkv2provider/schema_cloudflare_teams_rules.go
@@ -106,6 +106,11 @@ var teamsRuleSettings = map[string]*schema.Schema{
Optional: true,
Description: "Turns on IP category based filter on dns if the rule contains dns category checks.",
},
+ "ignore_cname_category_matches": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Set to true, to ignore the category matches at CNAME domains in a response.",
+ },
"allow_child_bypass": {
Type: schema.TypeBool,
Optional: true,
@@ -317,6 +322,11 @@ var teamsBisoAdminControls = map[string]*schema.Schema{
Optional: true,
Description: "Disable upload.",
},
+ "disable_clipboard_redirection": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Disable clipboard redirection.",
+ },
}
var teamsCheckSessionSettings = map[string]*schema.Schema{
@@ -339,11 +349,13 @@ var teamsDnsResolverSettings = map[string]*schema.Schema{
Elem: &schema.Resource{
Schema: teamsDnsResolverAddress,
},
+ MaxItems: 10,
Description: "IPv4 resolvers.",
},
"ipv6": {
Type: schema.TypeList,
Optional: true,
+ MaxItems: 10,
Elem: &schema.Resource{
Schema: teamsDnsResolverAddress,
},
diff --git a/internal/sdkv2provider/schema_cloudflare_zone_settings_override.go b/internal/sdkv2provider/schema_cloudflare_zone_settings_override.go
index 83ed28a967..1e268dc416 100644
--- a/internal/sdkv2provider/schema_cloudflare_zone_settings_override.go
+++ b/internal/sdkv2provider/schema_cloudflare_zone_settings_override.go
@@ -203,11 +203,1007 @@ var resourceCloudflareZoneSettingsSchema = map[string]*schema.Schema{
},
"mobile_redirect": {
- Type: schema.TypeList, // on/off
+ Type: schema.TypeList, // on/off
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Deprecated: "Mobile redirects has been deprecated and disabled in favour of [Single Redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/) and are no longer configurable using the API. Refer to [Perform mobile redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/examples/#perform-mobile-redirects) for examples of performing mobile redirects with Single Redirects.",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ // which parameters are mandatory is not specified
+ "mobile_subdomain": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+
+ "strip_uri": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+
+ "status": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+ },
+ },
+ },
+
+ "mirage": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "opportunistic_encryption": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "opportunistic_onion": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "origin_max_http_version": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"1", "2"}, false),
+ },
+
+ "polish": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "lossless", "lossy"}, false),
+ },
+
+ "webp": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ },
+
+ "prefetch_preload": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "privacy_pass": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "response_buffering": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "rocket_loader": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "manual"}, false),
+ },
+
+ "security_header": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "enabled": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "preload": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "max_age": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ },
+
+ "include_subdomains": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "nosniff": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+ },
+ },
+ },
+
+ "security_level": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "essentially_off", "low", "medium", "high", "under_attack"}, false),
+ },
+
+ "server_side_exclude": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ssl": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "flexible", "full", "strict", "origin_pull"}, false), // depends on plan
+ },
+
+ "universal_ssl": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ },
+
+ "tls_client_auth": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "true_client_ip_header": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "waf": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "min_tls_version": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"1.0", "1.1", "1.2", "1.3"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "tls_1_2_only": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ Deprecated: "tls_1_2_only has been deprecated in favour of using `min_tls_version = \"1.2\"` instead.",
+ },
+
+ "tls_1_3": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "zrt"}, false),
+ Optional: true,
+ Computed: true, // default depends on plan level
+ },
+
+ "automatic_https_rewrites": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "http2": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "http3": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "pseudo_ipv4": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "add_header", "overwrite_header"}, false),
+ },
+
+ "always_use_https": {
+ // may cause an error: HTTP status 400: content "{\"success\":false,\"errors\":[{\"code\":1016,\"message\":\"An unknown error has occurred\"}],\"messages\":[],\"result\":null}"
+ // but it still gets set at the API
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+
+ "cname_flattening": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"flatten_at_root", "flatten_all", "flatten_none"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "max_upload": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ },
+
+ "h2_prioritization": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "custom"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "image_resizing": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "open"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "zero_rtt": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "orange_to_orange": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "filter_logs_to_cloudflare": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "log_to_cloudflare": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "visitor_ip": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "proxy_read_timeout": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+
+ "binary_ast": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "early_hints": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "fonts": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "nel": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "enabled": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ },
+}
+
+var resourceCloudflareZoneSettingsSchemaV0 = map[string]*schema.Schema{
+ "always_online": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "brotli": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "browser_cache_ttl": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.IntInSlice([]int{0, 30, 60, 120, 300, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 28800,
+ 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 691200, 1382400, 2073600, 2678400, 5356800,
+ 16070400, 31536000}),
+ // minimum TTL available depends on the plan level of the zone.
+ // - Respect existing headers = 0
+ // - Enterprise = 30
+ // - Business, Pro, Free = 1800
+ },
+
+ "browser_check": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "cache_level": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"aggressive", "basic", "simplified"}, false),
+ },
+
+ "ciphers": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ },
+
+ "challenge_ttl": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.IntInSlice([]int{300, 900, 1800, 2700, 3600, 7200, 10800, 14400, 28800, 57600,
+ 86400, 604800, 2592000, 31536000}),
+ },
+
+ "development_mode": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "origin_error_page_pass_thru": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "sort_query_string_for_cache": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "email_obfuscation": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "hotlink_protection": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ip_geolocation": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ipv6": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "websockets": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "minify": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "css": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+
+ "html": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+
+ "js": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+ },
+ },
+ },
+
+ "mobile_redirect": {
+ Type: schema.TypeList, // on/off
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Deprecated: "Mobile redirects has been deprecated and disabled in favour of [Single Redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/) and are no longer configurable using the API. Refer to [Perform mobile redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/examples/#perform-mobile-redirects) for examples of performing mobile redirects with Single Redirects.",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ // which parameters are mandatory is not specified
+ "mobile_subdomain": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+
+ "strip_uri": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+
+ "status": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+ },
+ },
+ },
+
+ "mirage": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "opportunistic_encryption": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "opportunistic_onion": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "origin_max_http_version": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"1", "2"}, false),
+ },
+
+ "polish": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "lossless", "lossy"}, false),
+ },
+
+ "webp": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ },
+
+ "prefetch_preload": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "privacy_pass": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "response_buffering": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "rocket_loader": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "manual"}, false),
+ },
+
+ "security_header": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "enabled": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "preload": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "max_age": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ },
+
+ "include_subdomains": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+
+ "nosniff": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Computed: true,
+ },
+ },
+ },
+ },
+
+ "security_level": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "essentially_off", "low", "medium", "high", "under_attack"}, false),
+ },
+
+ "server_side_exclude": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ssl": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "flexible", "full", "strict", "origin_pull"}, false), // depends on plan
+ },
+
+ "universal_ssl": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ },
+
+ "tls_client_auth": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "true_client_ip_header": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "waf": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "min_tls_version": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"1.0", "1.1", "1.2", "1.3"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "tls_1_2_only": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ Deprecated: "tls_1_2_only has been deprecated in favour of using `min_tls_version = \"1.2\"` instead.",
+ },
+
+ "tls_1_3": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "zrt"}, false),
+ Optional: true,
+ Computed: true, // default depends on plan level
+ },
+
+ "automatic_https_rewrites": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "http2": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "http3": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "pseudo_ipv4": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"off", "add_header", "overwrite_header"}, false),
+ },
+
+ "always_use_https": {
+ // may cause an error: HTTP status 400: content "{\"success\":false,\"errors\":[{\"code\":1016,\"message\":\"An unknown error has occurred\"}],\"messages\":[],\"result\":null}"
+ // but it still gets set at the API
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+
+ "cname_flattening": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"flatten_at_root", "flatten_all", "flatten_none"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "max_upload": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ },
+
+ "h2_prioritization": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "custom"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "image_resizing": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off", "open"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "zero_rtt": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "orange_to_orange": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "filter_logs_to_cloudflare": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "log_to_cloudflare": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "visitor_ip": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "proxy_read_timeout": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+
+ "binary_ast": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "early_hints": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "fonts": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "nel": {
+ Type: schema.TypeList,
Optional: true,
Computed: true,
MinItems: 1,
MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "enabled": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ },
+}
+
+var resourceCloudflareZoneSettingsSchemaV1 = map[string]*schema.Schema{
+ "always_online": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "brotli": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "browser_cache_ttl": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.IntInSlice([]int{0, 30, 60, 120, 300, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 28800,
+ 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 691200, 1382400, 2073600, 2678400, 5356800,
+ 16070400, 31536000}),
+ // minimum TTL available depends on the plan level of the zone.
+ // - Respect existing headers = 0
+ // - Enterprise = 30
+ // - Business, Pro, Free = 1800
+ },
+
+ "browser_check": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "cache_level": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringInSlice([]string{"aggressive", "basic", "simplified"}, false),
+ },
+
+ "ciphers": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ },
+
+ "challenge_ttl": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.IntInSlice([]int{300, 900, 1800, 2700, 3600, 7200, 10800, 14400, 28800, 57600,
+ 86400, 604800, 2592000, 31536000}),
+ },
+
+ "development_mode": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "origin_error_page_pass_thru": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "sort_query_string_for_cache": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "email_obfuscation": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "hotlink_protection": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ip_geolocation": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "ipv6": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "websockets": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Optional: true,
+ Computed: true,
+ },
+
+ "minify": {
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Deprecated: "Auto Minify has been deprecated and disabled",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "css": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+
+ "html": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+
+ "js": {
+ Type: schema.TypeString,
+ ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
+ Required: true,
+ },
+ },
+ },
+ },
+
+ "mobile_redirect": {
+ Type: schema.TypeList, // on/off
+ Optional: true,
+ Computed: true,
+ MinItems: 1,
+ MaxItems: 1,
+ Deprecated: "Mobile redirects has been deprecated and disabled in favour of [Single Redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/) and are no longer configurable using the API. Refer to [Perform mobile redirects](https://developers.cloudflare.com/rules/url-forwarding/single-redirects/examples/#perform-mobile-redirects) for examples of performing mobile redirects with Single Redirects.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
// which parameters are mandatory is not specified
diff --git a/scripts/generate-changelog.sh b/scripts/generate-changelog.sh
index dbd0c3775f..a9748eef16 100755
--- a/scripts/generate-changelog.sh
+++ b/scripts/generate-changelog.sh
@@ -24,7 +24,7 @@ then
exit 1
fi
-CHANGELOG=$($(go env GOPATH)/bin/changelog-build -this-release $TARGET_SHA \
+CHANGELOG=$(changelog-build -this-release $TARGET_SHA \
-last-release $PREVIOUS_RELEASE_SHA \
-git-dir $__parent \
-entries-dir .changelog \
diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh
index a5bef4d892..2debd3b804 100755
--- a/scripts/generate-docs.sh
+++ b/scripts/generate-docs.sh
@@ -7,13 +7,13 @@ exclude_files=()
# Check if manual changes were made to any excluded files and exit
# otherwise these will be lost with `tfplugindocs`
-if [ "$(git status --porcelain "${exclude_files[@]}")" ]; then
- echo "Uncommitted changes were detected to the following files. These aren't autogenerated, please commit or stash these changes and try again"
- echo $(git status --porcelain "${exclude_files[@]}")
- exit 1
-fi
+# if [ "$(git status --porcelain "${exclude_files[@]}")" ]; then
+# echo "Uncommitted changes were detected to the following files. These aren't autogenerated, please commit or stash these changes and try again"
+# echo $(git status --porcelain "${exclude_files[@]}")
+# exit 1
+# fi
-$(go env GOPATH)/bin/tfplugindocs generate\
+tfplugindocs generate\
-rendered-provider-name "Cloudflare"
# Remove the changes to files we don't autogenerate
diff --git a/templates/resources/filter.md.tmpl b/templates/resources/filter.md.tmpl
index 27b5ee7154..39f7167092 100644
--- a/templates/resources/filter.md.tmpl
+++ b/templates/resources/filter.md.tmpl
@@ -9,8 +9,8 @@ description: |-
{{ .Description | trimspace }}
-~> `cloudflare_filter` is in a deprecation phase that will last for 14 months
- (July 1st, 2024). During this time period, this resource is still fully
+~> `cloudflare_filter` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still fully
supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users).
diff --git a/templates/resources/firewall_rule.md.tmpl b/templates/resources/firewall_rule.md.tmpl
index 2602a5793a..286338e7bf 100644
--- a/templates/resources/firewall_rule.md.tmpl
+++ b/templates/resources/firewall_rule.md.tmpl
@@ -9,8 +9,8 @@ description: |-
{{ .Description | trimspace }}
-~> `cloudflare_firewall_rule` is in a deprecation phase that will last for 14
- months (July 1st, 2024). During this time period, this resource is still
+~> `cloudflare_firewall_rule` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still
fully supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/firewall-rules-to-custom-rules/#relevant-changes-for-terraform-users).
diff --git a/templates/resources/rate_limit.md.tmpl b/templates/resources/rate_limit.md.tmpl
index d59f14fad7..1ee9912082 100644
--- a/templates/resources/rate_limit.md.tmpl
+++ b/templates/resources/rate_limit.md.tmpl
@@ -9,8 +9,8 @@ description: |-
{{ .Description | trimspace }}
-~> `cloudflare_rate_limit` is in a deprecation phase that will last for 14
- months (July 1st, 2024). During this time period, this resource is still
+~> `cloudflare_rate_limit` is in a deprecation phase until January 15th, 2025.
+ During this time period, this resource is still
fully supported but you are strongly advised to move to the
`cloudflare_ruleset` resource. Full details can be found in the
[developer documentation](https://developers.cloudflare.com/waf/reference/migration-guides/old-rate-limiting-deprecation/#relevant-changes-for-terraform-users).
diff --git a/templates/resources/zero_trust_access_application.md.tmpl b/templates/resources/zero_trust_access_application.md.tmpl
new file mode 100644
index 0000000000..5818d47ec9
--- /dev/null
+++ b/templates/resources/zero_trust_access_application.md.tmpl
@@ -0,0 +1,33 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
+{{- end }}
diff --git a/templates/resources/zero_trust_access_group.md.tmpl b/templates/resources/zero_trust_access_group.md.tmpl
new file mode 100644
index 0000000000..049f3f5361
--- /dev/null
+++ b/templates/resources/zero_trust_access_group.md.tmpl
@@ -0,0 +1,31 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
diff --git a/templates/resources/zero_trust_access_identity_provider.md.tmpl b/templates/resources/zero_trust_access_identity_provider.md.tmpl
new file mode 100644
index 0000000000..049f3f5361
--- /dev/null
+++ b/templates/resources/zero_trust_access_identity_provider.md.tmpl
@@ -0,0 +1,31 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
diff --git a/templates/resources/zero_trust_access_mtls_certificate.md.tmpl b/templates/resources/zero_trust_access_mtls_certificate.md.tmpl
new file mode 100644
index 0000000000..049f3f5361
--- /dev/null
+++ b/templates/resources/zero_trust_access_mtls_certificate.md.tmpl
@@ -0,0 +1,31 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
diff --git a/templates/resources/zero_trust_access_policy.md.tmpl b/templates/resources/zero_trust_access_policy.md.tmpl
new file mode 100644
index 0000000000..e88296831c
--- /dev/null
+++ b/templates/resources/zero_trust_access_policy.md.tmpl
@@ -0,0 +1,33 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in most cases using either is fine.
+ However, if you're using a scoped access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com" zone needs to use the `zone_id` argument.
+ If 'application_id' is omitted, the policy created can be reused by multiple access applications.
+ Any cloudflare_access_application resource can reference reusable policies through its `policies` argument.
+ To destroy a reusable policy and remove it from all applications' policies lists on the same apply, preemptively set the
+ lifecycle option `create_before_destroy` to true on the 'cloudflare_access_policy' resource.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
diff --git a/templates/resources/zero_trust_access_short_lived_certificate.md.tmpl b/templates/resources/zero_trust_access_short_lived_certificate.md.tmpl
new file mode 100644
index 0000000000..049f3f5361
--- /dev/null
+++ b/templates/resources/zero_trust_access_short_lived_certificate.md.tmpl
@@ -0,0 +1,31 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+~> It's required that an `account_id` or `zone_id` is provided and in
+ most cases using either is fine. However, if you're using a scoped
+ access token, you must provide the argument that matches the token's
+ scope. For example, an access token that is scoped to the "example.com"
+ zone needs to use the `zone_id` argument.
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{codefile "terraform" .ExampleFile}}
+{{- end }}
+{{ .SchemaMarkdown | trimspace }}
+
+{{ if .HasImport -}}
+## Import
+
+Import is supported using the following syntax:
+
+{{codefile "shell" .ImportFile}}
+{{- end }}
diff --git a/tools/go.mod b/tools/go.mod
index 92163dfa24..7bfbae6320 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -73,7 +73,7 @@ require (
github.com/emirpasic/gods v1.18.1 // indirect
github.com/esimonov/ifshort v1.0.4 // indirect
github.com/ettle/strcase v0.1.1 // indirect
- github.com/fatih/color v1.15.0 // indirect
+ github.com/fatih/color v1.16.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/firefart/nonamedreturns v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
@@ -119,7 +119,7 @@ require (
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
+ github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
@@ -154,7 +154,7 @@ require (
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
@@ -244,7 +244,7 @@ require (
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.4.0 // indirect
- golang.org/x/sys v0.18.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.14.0 // indirect
diff --git a/tools/go.sum b/tools/go.sum
index 02b796ddaf..fb761fc534 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -230,8 +230,8 @@ github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcH
github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y=
@@ -449,7 +449,7 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
+github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
@@ -457,8 +457,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
-github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
-github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
+github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
+github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@@ -621,8 +621,8 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
-github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -1174,8 +1174,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=