How to use Terraform to manage HOLE Foundation infrastructure across all cloud providers (Cloudflare, Azure, AWS)
/plugin marketplace add The-HOLE-Foundation/claude-plugins/plugin install the-hole-foundation-hole-infrastructure-hole-infrastructure@The-HOLE-Foundation/claude-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
All HOLE Foundation infrastructure is managed via Terraform with state stored in Terraform Cloud.
Terraform Root: /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/
Terraform Cloud Org: theholetruth
Backend: Remote (Terraform Cloud)
Providers: Cloudflare, Azure, AWS
/Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/
├── cloudflare/
│ ├── foundation/ # Foundation account (387 resources) ✅
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ ├── tf-with-dotenvx.sh ⭐
│ │ └── [24 .tf files]
│ └── personal/ # Personal account (~20 resources) ⏳
│ ├── main.tf
│ ├── backend.tf
│ └── [3 .tf files]
│
├── production/ # Azure (alias: azure/)
│ ├── main.tf # Entra DS infrastructure
│ ├── backend.tf
│ └── outputs.tf
│
├── aws/
│ └── foundation/ # AWS Bedrock (~5 resources)
│ ├── main.tf
│ ├── backend.tf
│ ├── bedrock.tf
│ └── outputs.tf
│
├── dev/ # Development workspace (all providers)
└── shared/ # Shared modules (future)
| Workspace | Provider | Local Path | State |
|---|---|---|---|
cloudflare-foundation-prod | Cloudflare | cloudflare/foundation/ | 387 resources |
cloudflare-personal-prod | Cloudflare | cloudflare/personal/ | ~20 resources |
azure-hole-general-services-prod | Azure | production/ | ~10 resources |
aws-foundation-prod | AWS | aws/foundation/ | ~5 resources |
Organization: theholetruth
Total Resources: ~422 across 4 workspaces
Location: terraform/cloudflare/foundation/
Secrets: Auto-loaded via wrapper script
Commands:
cd /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/cloudflare/foundation
# Use wrapper script (auto-loads CLOUDFLARE_API_TOKEN from dotenvx)
./tf-with-dotenvx.sh plan
./tf-with-dotenvx.sh apply
./tf-with-dotenvx.sh state list
./tf-with-dotenvx.sh import <resource> <id>
Why wrapper? Automatically loads CF_API_TOKEN and TF_VAR_cloudflare_api_token from dotenvx.
Location: terraform/production/
Authentication: Azure CLI (no secrets needed)
Commands:
cd /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/production
# Verify Azure CLI authentication
az account show
# Standard Terraform commands
terraform plan
terraform apply
terraform state list
Why no wrapper? Azure uses Azure CLI authentication (joe@theholetruth.org already logged in).
Location: terraform/aws/foundation/
Secrets: Manual loading from dotenvx
Commands:
cd /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/aws/foundation
# Load AWS credentials from dotenvx
export AWS_ACCESS_KEY_ID=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_ACCESS_KEY_ID)
export AWS_SECRET_ACCESS_KEY=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_SECRET_ACCESS_KEY)
export TF_VAR_aws_access_key="$AWS_ACCESS_KEY_ID"
export TF_VAR_aws_secret_key="$AWS_SECRET_ACCESS_KEY"
# Standard Terraform commands
terraform plan
terraform apply
terraform state list
Make changes to .tf files:
terraform fmt -recursive # Format all .tf files
terraform validate # Check syntax
terraform plan
What plan shows:
+ Resources to create~ Resources to modify- Resources to delete→ Resources to replaceALWAYS:
terraform apply
With auto-approve (use caution):
terraform apply -auto-approve
Provider-specific verification:
az CLI to verifyaws CLI to verify# List all resources
terraform state list
# Show specific resource
terraform state show <resource-address>
# Pull state file (backup)
terraform state pull > state-backup.json
# Import existing resource into Terraform
terraform import <resource-type>.<name> <resource-id>
# Example: Import Cloudflare zone
terraform import cloudflare_zone.example 1a2b3c4d5e6f7g8h9i0j
# Remove from state only (doesn't delete in provider)
terraform state rm <resource-address>
# Destroy resource (deletes in provider)
terraform destroy -target=<resource-address>
# Show current workspace
terraform workspace show
# List all workspaces
terraform workspace list
# Switch workspace (if using local workspaces)
terraform workspace select <name>
Note: HOLE Foundation uses Terraform Cloud workspaces (separate directories), not local workspaces.
User: "Deploy this AI-enhanced web app"
Required Changes:
Cloudflare (terraform/cloudflare/foundation/)
AWS (terraform/aws/foundation/)
Workflow:
# 1. Update Cloudflare workspace
cd /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/cloudflare/foundation
# Edit .tf files
./tf-with-dotenvx.sh plan
./tf-with-dotenvx.sh apply
# 2. Update AWS workspace
cd /Volumes/HOLE-RAID-DRIVE/Projects/hole-terraformer/terraform/aws/foundation
# Load AWS credentials
export AWS_ACCESS_KEY_ID=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_ACCESS_KEY_ID)
export AWS_SECRET_ACCESS_KEY=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_SECRET_ACCESS_KEY)
export TF_VAR_aws_access_key="$AWS_ACCESS_KEY_ID"
export TF_VAR_aws_secret_key="$AWS_SECRET_ACCESS_KEY"
# Edit .tf files
terraform plan
terraform apply
# 3. Verify both providers
# Test Cloudflare Worker
# Test AWS Lambda
# Test integration
✅ Team collaboration - Multiple people can work safely ✅ State locking - Prevents concurrent modifications ✅ Version history - Can rollback to previous states ✅ Secure storage - State never stored locally ✅ Access control - Manage who can apply changes
Via CLI (local execution):
terraform plan # Creates speculative plan
terraform apply # Creates and applies run
Via Terraform Cloud UI (optional):
Via API (if using Terraform MCP):
create_run toolRecommended workflow:
# 1. Make Terraform changes
vim cloudflare_zone.tf
# 2. Format
terraform fmt
# 3. Test locally
terraform plan
# 4. Commit
git add cloudflare_zone.tf
git commit -m "feat: Add new zone for newdomain.org"
# 5. Push
git push
# 6. Apply (could be automated via CI/CD)
terraform apply
✅ DO commit:
❌ NEVER commit:
Problem: "workspace already locked"
Solution:
# Force unlock (use with caution)
terraform force-unlock -force "<lock-id>"
# For Terraform Cloud workspaces
terraform force-unlock -force "theholetruth/<workspace-name>"
Cloudflare:
# Verify token is loaded
echo "Token length: ${#CF_API_TOKEN}"
# Should be 40
# Reload from dotenvx
export CF_API_TOKEN=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get CLOUDFLARE_API_TOKEN)
Azure:
# Re-authenticate
az login
az account set --subscription "de602062-dafa-4c8b-91b7-98a75bcd7cff"
AWS:
# Reload credentials
export AWS_ACCESS_KEY_ID=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_ACCESS_KEY_ID)
export AWS_SECRET_ACCESS_KEY=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_SECRET_ACCESS_KEY)
Problem: Plan shows changes you didn't make
Causes:
Solutions:
lifecycle { ignore_changes = [...] }When HashiCorp Terraform MCP server is loaded (Phase 2), use these tools:
list_workspaces - See all 4 workspacesget_workspace - Get workspace detailscreate_workspace - Create new workspaceupdate_workspace - Modify workspace settingsdelete_workspace - Remove workspacelist_workspace_variables - See all variablescreate_workspace_variable - Add secret/configupdate_workspace_variable - Modify variabledelete_workspace_variable - Remove variablecreate_run - Execute plan or applyget_run - Check run statuslist_runs - View run historycancel_run - Stop running operationlist_state_versions - View state historyget_current_state - Download current staterollback_state - Restore previous stateKey Benefit: MCP tools work for ALL providers - same tools for Cloudflare, Azure, AWS!
When deploying across multiple providers:
Pattern 1: Cloudflare Worker → AWS Lambda
# Cloudflare (terraform/cloudflare/foundation/)
resource "cloudflare_worker_script" "api" {
# ...
# Environment variable points to AWS Lambda
plain_text_binding {
name = "AWS_LAMBDA_URL"
text = "<lambda-function-url>" # From AWS outputs
}
}
# AWS (terraform/aws/foundation/)
resource "aws_lambda_function" "ai_processor" {
# ...
}
resource "aws_lambda_function_url" "ai_processor" {
function_name = aws_lambda_function.ai_processor.function_name
authorization_type = "NONE" # Or AWS_IAM with Worker auth
}
output "lambda_url" {
value = aws_lambda_function_url.ai_processor.function_url
}
Workflow:
Pattern 2: Multi-Provider Application
For full-stack apps requiring Cloudflare + AWS:
cd terraform/cloudflare/foundation
./tf-with-dotenvx.sh plan
./tf-with-dotenvx.sh apply
cd terraform/production
terraform plan
terraform apply
cd terraform/aws/foundation
export AWS_ACCESS_KEY_ID=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_ACCESS_KEY_ID)
export AWS_SECRET_ACCESS_KEY=$(cd /Volumes/HOLE-RAID-DRIVE/dotenvx && dotenvx get AWS_SECRET_ACCESS_KEY)
export TF_VAR_aws_access_key="$AWS_ACCESS_KEY_ID"
export TF_VAR_aws_secret_key="$AWS_SECRET_ACCESS_KEY"
terraform plan
terraform apply
Before running terraform apply on ANY provider:
pwd)terraform plan? (NEVER skip!)Special for Azure:
Option 1: Revert Terraform config
git revert <commit-hash>
terraform plan
terraform apply
Option 2: Restore previous state (via Terraform Cloud UI)
terraform force-unlock -force "<lock-id>"
# For Terraform Cloud workspaces
terraform force-unlock -force "theholetruth/<workspace-name>"
Cloudflare: Changes are usually instant - rollback via Terraform Azure: Critical for SSO - test rollback procedure in advance AWS: Lambda/resources can be rolled back via Terraform
Use -target for specific resources:
terraform plan -target=cloudflare_record.api
Use -refresh=false to skip state refresh:
terraform plan -refresh=false
Terraform automatically parallelizes operations where possible. For multi-provider deployments, run workspaces in parallel:
# Terminal 1: Cloudflare
cd terraform/cloudflare/foundation
./tf-with-dotenvx.sh apply &
# Terminal 2: AWS
cd terraform/aws/foundation
terraform apply &
# Wait for both
wait
This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.