@@ -1,181 +1,230 @@
#!/bin/ bash
#!/usr/bin/env bash
set -euo pipefail
cf_generate ( ) {
resources = (
cloudflare_account
cloudflare_account_member
cloudflare_account_subscription
cloudflare_address_map
cloudflare_api_shield_discovery_operation
cloudflare_api_shield_operation
cloudflare_api_shield_operation_schema_validation_settings
cloudflare_api_shield_schema
cloudflare_api_shield_schema_validation_settings
cloudflare_argo_smart_routing
cloudflare_argo_tiered_caching
cloudflare_authenticated_origin_pulls
cloudflare_authenticated_origin_pulls_certificate
cloudflare_bot_management
cloudflare_calls_sfu_app
cloudflare_calls_turn_app
cloudflare_certificate_pack
cloudflare_content_scanning_expression
cloudflare_custom_hostname
cloudflare_custom_hostname_fallback_origin
cloudflare_d1_database
cloudflare_dns_firewall
cloudflare_dns_record
cloudflare_dns_zone_transfers_acl
cloudflare_dns_zone_transfers_incoming
cloudflare_dns_zone_transfers_outgoing
cloudflare_dns_zone_transfers_peer
cloudflare_dns_zone_transfers_tsig
cloudflare_email_routing_address
cloudflare_email_routing_catch_all
cloudflare_email_routing_dns
cloudflare_email_routing_rule
cloudflare_email_routing_settings
cloudflare_email_security_block_sender
cloudflare_email_security_impersonation_registry
cloudflare_email_security_trusted_domains
cloudflare_filter
cloudflare_healthcheck
cloudflare_hostname_tls_setting
cloudflare_keyless_certificate
cloudflare_leaked_credential_check
cloudflare_leaked_credential_check_rule
cloudflare_list
cloudflare_list_item
cloudflare_load_balancer
cloudflare_load_balancer_monitor
cloudflare_load_balancer_pool
cloudflare_logpull_retention
cloudflare_logpush_job
cloudflare_magic_wan_static_route
cloudflare_managed_transforms
cloudflare_mtls_certificate
cloudflare_notification_policy
cloudflare_notification_policy_webhooks
cloudflare_observatory_scheduled_test
cloudflare_origin_ca_certificate
cloudflare_page_rule
cloudflare_page_shield_policy
cloudflare_pages_domain
cloudflare_pages_project
cloudflare_queue
cloudflare_queue_consumer
cloudflare_r2_bucket
cloudflare_r2_custom_domain
cloudflare_r2_managed_domain
cloudflare_rate_limit
cloudflare_regional_hostname
cloudflare_regional_tiered_cache
cloudflare_registrar_domain
cloudflare_ruleset
cloudflare_snippet_rules
cloudflare_snippets
cloudflare_spectrum_application
cloudflare_stream
cloudflare_stream_key
cloudflare_stream_live_input
cloudflare_stream_watermark
cloudflare_stream_webhook
cloudflare_tiered_cache
cloudflare_total_tls
cloudflare_turnstile_widget
cloudflare_url_normalization_settings
cloudflare_user
cloudflare_waiting_room
cloudflare_waiting_room_event
cloudflare_waiting_room_rules
cloudflare_waiting_room_settings
cloudflare_web3_hostname
cloudflare_web_analytics_rule
cloudflare_web_analytics_site
cloudflare_workers_cron_trigger
cloudflare_workers_custom_domain
cloudflare_workers_deployment
cloudflare_workers_for_platforms_dispatch_namespace
cloudflare_workers_kv_namespace
cloudflare_workers_script_subdomain
cloudflare_zero_trust_access_application
cloudflare_zero_trust_access_custom_page
cloudflare_zero_trust_access_group
cloudflare_zero_trust_access_identity_provider
cloudflare_zero_trust_access_infrastructure_target
cloudflare_zero_trust_access_key_configuration
cloudflare_zero_trust_access_mtls_certificate
cloudflare_zero_trust_access_mtls_hostname_settings
cloudflare_zero_trust_access_policy
cloudflare_zero_trust_access_service_token
cloudflare_zero_trust_access_short_lived_certificate
cloudflare_zero_trust_access_tag
cloudflare_zero_trust_device_custom_profile
cloudflare_zero_trust_device_default_profile
cloudflare_zero_trust_device_default_profile_certificates
cloudflare_zero_trust_device_default_profile_local_domain_fallback
cloudflare_zero_trust_device_managed_networks
cloudflare_zero_trust_device_posture_integration
cloudflare_zero_trust_device_posture_rule
cloudflare_zero_trust_dex_test
cloudflare_zero_trust_dlp_custom_profile
cloudflare_zero_trust_dlp_dataset
cloudflare_zero_trust_dlp_predefined_profile
cloudflare_zero_trust_dns_location
cloudflare_zero_trust_gateway_certificate
cloudflare_zero_trust_gateway_policy
cloudflare_zero_trust_gateway_proxy_endpoint
cloudflare_zero_trust_gateway_settings
cloudflare_zero_trust_list
cloudflare_zero_trust_organization
cloudflare_zero_trust_risk_behavior
cloudflare_zero_trust_risk_scoring_integration
cloudflare_zero_trust_tunnel_cloudflared
cloudflare_zero_trust_tunnel_cloudflared_config
cloudflare_zero_trust_tunnel_cloudflared_route
cloudflare_zero_trust_tunnel_cloudflared_virtual_network
cloudflare_zone
cloudflare_zone_cache_reserve
cloudflare_zone_cache_variants
cloudflare_zone_dnssec
cloudflare_zone_lockdown
cloudflare_zone_setting
)
# -------------------------------
# Detect Terraform binary: tofu vs terraform
# -------------------------------
if command -v tofu & >/dev/null; then
TF_BIN = "tofu"
elif command -v terraform & >/dev/null; then
TF_BIN = "terraform"
else
echo "❌ Neither 'terraform' nor 'tofu' found in PATH"
exit 1
fi
for resource in " ${ resources [@] } " ; do
echo " Generating ${ resource } .tf... "
cf-terraforming generate --zone ${ CLOUDFLARE_ZONE_ID } --resource-type ${ resource } > ${ resource } .tf
done
echo " ℹ ️ Using $TF_BIN for Terraform operations "
echo "🧹 Cleaning up empty files..."
find . -size 0 -name "*.tf" | xargs rm
echo "✅ All Terraform files generated!"
# -------------------------------
# Ensure CF API token
# -------------------------------
CF_API_TOKEN = " ${ CLOUDFLARE_API_TOKEN :- } "
if [ [ -z " ${ CF_API_TOKEN } " ] ] ; then
echo "Please set CF_API_TOKEN before running this script."
exit 1
fi
# -------------------------------
# Helper: fetch paginated results from Cloudflare API
# -------------------------------
cf_paginate( ) {
local endpoint = " $1 "
local page = 1
local per_page = 100
while :; do
local result
result = $( curl -s -X GET " ${ endpoint } ?page= ${ page } &per_page= ${ per_page } " \
-H " Authorization: Bearer ${ CF_API_TOKEN } " \
-H "Content-Type: application/json" )
local items
items = $( echo " ${ result } " | jq -r '.result[]? | @base64' )
[ [ -z " $items " ] ] && break
echo " $items "
local total_pages
total_pages = $( echo " $result " | jq -r '.result_info.total_pages' )
( ( page++) )
[ [ $page -gt $total_pages ] ] && break
done
}
cf_import ( ) {
for cfresource in $( find . -type f -name "cloudflare_*.tf" ) ; do
echo " Importing ${ cfresource } ... "
cf-terraforming import --zone ${ CLOUDFLARE_ZONE_ID } --modern-import-block --resource-type $( echo ${ cfresource } | sed -e 's/.\///' -e 's/\.tf//' ) >> imports.tf
done
# -------------------------------
# Generate Cloudflare resources using cf-terraforming
# -------------------------------
generate_resources( ) {
echo "🔧 Generating Cloudflare resources via cf-terraforming..."
local output_file = "cloudflare_resource_gen.tf"
> " ${ output_file } "
echo "✅ All Cloudflare resources imported. Please check imports.tf"
resources = (
cloudflare_account
cloudflare_account_member
cloudflare_account_subscription
cloudflare_address_map
cloudflare_argo_tiered_caching
cloudflare_authenticated_origin_pulls
cloudflare_authenticated_origin_pulls_certificate
cloudflare_bot_management
cloudflare_certificate_pack
cloudflare_content_scanning_expression
cloudflare_custom_hostname
cloudflare_custom_hostname_fallback_origin
cloudflare_d1_database
cloudflare_dns_firewall
cloudflare_dns_record
cloudflare_dns_zone_transfers_acl
cloudflare_dns_zone_transfers_incoming
cloudflare_dns_zone_transfers_outgoing
cloudflare_dns_zone_transfers_peer
cloudflare_dns_zone_transfers_tsig
cloudflare_email_routing_address
cloudflare_email_routing_catch_all
cloudflare_email_routing_dns
cloudflare_email_routing_rule
cloudflare_email_routing_settings
cloudflare_filter
cloudflare_healthcheck
cloudflare_hostname_tls_setting
cloudflare_keyless_certificate
cloudflare_leaked_credential_check
cloudflare_leaked_credential_check_rule
cloudflare_list_item
cloudflare_load_balancer
cloudflare_load_balancer_monitor
cloudflare_load_balancer_pool
cloudflare_logpull_retention
cloudflare_logpush_job
cloudflare_magic_wan_static_route
cloudflare_managed_transforms
cloudflare_mtls_certificate
cloudflare_notification_policy
cloudflare_notification_policy_webhooks
cloudflare_observatory_scheduled_test
cloudflare_origin_ca_certificate
cloudflare_page_rule
cloudflare_page_shield_policy
cloudflare_pages_domain
cloudflare_pages_project
cloudflare_queue
cloudflare_queue_consumer
cloudflare_r2_bucket
cloudflare_r2_custom_domain
cloudflare_r2_managed_domain
cloudflare_rate_limit
cloudflare_regional_hostname
cloudflare_regional_tiered_cache
cloudflare_registrar_domain
cloudflare_ruleset
cloudflare_snippet_rules
cloudflare_snippets
cloudflare_spectrum_application
cloudflare_stream
cloudflare_stream_key
cloudflare_stream_live_input
cloudflare_stream_watermark
cloudflare_stream_webhook
cloudflare_tiered_cache
cloudflare_total_tls
cloudflare_turnstile_widget
cloudflare_url_normalization_settings
cloudflare_user
cloudflare_waiting_room
cloudflare_waiting_room_event
cloudflare_waiting_room_rules
cloudflare_waiting_room_settings
cloudflare_web3_hostname
cloudflare_web_analytics_rule
cloudflare_web_analytics_site
cloudflare_workers_cron_trigger
cloudflare_workers_custom_domain
cloudflare_workers_deployment
cloudflare_workers_for_platforms_dispatch_namespace
cloudflare_workers_kv_namespace
cloudflare_workers_script_subdomain
cloudflare_zone
cloudflare_zone_cache_reserve
cloudflare_zone_cache_variants
cloudflare_zone_dnssec
cloudflare_zone_lockdown
cloudflare_zone_setting
)
for r in " ${ resources [@] } " ; do
echo " Generating $r ... "
cf-terraforming generate \
--token " ${ CF_API_TOKEN } " \
--resource-type " ${ r } " >> " ${ output_file } " || true
done
echo " ✅ Terraform resources generated in ${ output_file } "
}
# Prompt user for input
# -------------------------------
# Import Cloudflare resources into state using cf-terraforming
# -------------------------------
import_zone_resources( ) {
local zone_id = " $1 "
local zone_name = " $2 "
echo " ⏳ Importing zone $zone_name ... "
cf-terraforming import \
--token " ${ CF_API_TOKEN } " \
--modern-import-block \
--resource-type cloudflare_zone \
--resource-id " $zone_id " >> cloudflare_resource_imp.tf || true
echo " ✅ Imported cloudflare_zone for $zone_name "
echo " 🔄 Importing DNS records for $zone_name ... "
cf-terraforming import \
--token " ${ CF_API_TOKEN } " \
--zone " $zone_id " \
--modern-import-block \
--resource-type cloudflare_dns_record >> cloudflare_resource_imp.tf || true
echo " ✅ Imported DNS records for $zone_name "
# Optional: import other zone-level resources
for res in cloudflare_argo_tiered_caching cloudflare_email_routing_settings cloudflare_tiered_cache cloudflare_zone_dnssec; do
cf-terraforming import \
--token " ${ CF_API_TOKEN } " \
--resource-type " $res " \
--modern-import-block \
--resource-id " $zone_id " >> cloudflare_resource_imp.tf || true
echo " ✅ Imported $res for $zone_name "
done
}
# -------------------------------
# Main
# -------------------------------
echo "Choose an option:"
echo "1) Generate Cloudflare Terraform resources"
echo "2) Import Cloudflare Terraform resources"
read -rp "Enter 1 or 2: " user_ choice
echo "2) Import Cloudflare Terraform resources into state "
read -rp "Enter 1 or 2: " choice
case " $user_ choice " in
1)
cf_ generate
; ;
2)
cf_import
; ;
*)
echo "Invalid option. Please enter 1 or 2."
exit 1
; ;
case " $choice " in
1)
generate_resources
; ;
2)
echo "🔄 Fetching zones..."
zones = $( cf_paginate "https://api.cloudflare.com/client/v4/zones" )
declare -A zone_map
while read -r z; do
zname = $( echo " $z " | base64 --decode | jq -r '.name' )
zid = $( echo " $z " | base64 --decode | jq -r '.id' )
zone_map[ " $zname " ] = " $zid "
done <<< " $zones "
echo " ⚡ Found ${# zone_map [@] } zones. "
for zone_name in " ${ !zone_map[@] } " ; do
zid = " ${ zone_map [ $zone_name ] } "
import_zone_resources " $zid " " $zone_name "
done
; ;
*)
echo "Invalid option. Enter 1 or 2."
exit 1
; ;
esac
echo "🎉 All operations completed!"