# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview AWS CloudFront CDN with CrowdSec real-time security integration via Lambda. Implements automated IP blocking through webhook notifications. ## Common Development Commands ### Infrastructure Management ```bash # Initialize OpenTofu (required after cloning) tofu init # Plan changes tofu plan # Apply changes tofu apply # Destroy infrastructure tofu destroy ``` ### Backend Setup (S3 + CloudFront Logs) ```bash # Set up S3 backend and CloudFront logging buckets ./setup-backend.sh # Migrate state to S3 backend (one-time operation) echo "yes" | tofu init -migrate-state ``` ### Validation and Formatting ```bash # Validate configuration tofu validate # Format files tofu fmt # Check syntax and validate variables tofu plan -var-file=terraform.tfvars ``` ### AWS Resource Verification ```bash # Check CloudFront distribution status (Current Distribution ID: EATJ1HDQU8V51) aws cloudfront get-distribution --id EATJ1HDQU8V51 --query 'Distribution.Status' --output text # List all CloudFront distributions aws cloudfront list-distributions --query 'DistributionList.Items[*].[Id,Status,DistributionConfig.Enabled]' --output table # Check S3 backend state aws s3 ls s3://aws-cf-terraform-state-535294143817/aws-cf/ # View CloudFront logs aws s3 ls s3://aws-cf-cloudfront-logs-535294143817/cloudfront-logs/ --recursive ``` ## Architecture Overview ### Infrastructure Design This is an AWS CloudFront CDN deployment using OpenTofu (Terraform fork) with the following key architectural decisions: **Primary Components:** - **CloudFront Distribution**: Main CDN with custom origin server - **WAF v2 Web ACL**: Security layer with rate limiting and AWS managed rules - **S3 Backend**: Remote state storage with versioning and encryption - **CrowdSec Integration**: Real-time threat detection and IP blocking **Critical Configuration Constraints:** - Origin server (`origin.servidor.it.com`) only supports HTTP, not HTTPS - Using CloudFront default certificate (not custom ACM certificate) - Route53 records disabled due to CAA restrictions - DynamoDB state locking disabled due to permission constraints ### File Structure and Responsibilities **Core Infrastructure:** - `main.tf` - CloudFront distribution, origin configuration, cache behaviors - `security.tf` - WAF Web ACL with rate limiting, managed rule sets, and security groups - `lambda.tf` - CrowdSec Lambda integration with API Gateway - `lambda-crowdsec-waf.py` - Lambda function for real-time IP management - `variables.tf` - All configurable parameters with validation rules - `outputs.tf` - CloudFront URLs, distribution IDs, and resource ARNs **Configuration Management:** - `backend.tf` - S3 remote state configuration (no DynamoDB locking) - `versions.tf` - OpenTofu/Terraform and provider version constraints - `acm.tf` - ACM certificate configuration (currently disabled) - `terraform.tfvars.example` - Variable configuration template **Operational Scripts:** - `setup-backend.sh` - Automated S3 backend and logging bucket creation with proper permissions ### Key Architectural Patterns **Multi-Environment Design:** - Variables for `project_name` and `environment` enable multiple deployments - Resource naming follows `${project_name}-${environment}-${resource}` pattern - Tags applied consistently across all resources **Security-First Approach:** - WAF protection with AWS managed rules and rate limiting - S3 buckets with encryption, versioning, and public access blocking - Security groups with principle of least privilege (when VPC enabled) - CrowdSec real-time threat detection with Lambda integration **Cache Strategy:** - Default behavior uses CachingDisabled policy for dynamic content - API paths (`/api/*`) specifically configured with caching disabled - Static content can be optimized by changing cache policy IDs **Conditional Resource Creation:** - Most resources controlled by boolean variables for flexible deployment - ACM certificates, Route53 records, and CloudFormation stacks can be toggled - Allows gradual feature enablement as permissions are acquired ## Important Configuration Notes ### Critical Settings in terraform.tfvars - `origin_protocol_policy = "http-only"` - **Do not change to HTTPS** (causes 504 errors) - `create_acm_certificate = true` - ACM certificate enabled for custom domain - `enable_waf = true` - WAF is working and provides important security - `create_route53_records = true` - Route53 DNS management enabled ### State Management - Backend uses S3 without DynamoDB locking (single developer setup) - State bucket: `aws-cf-terraform-state-535294143817` - Logs bucket: `aws-cf-cloudfront-logs-535294143817` ### Security Considerations - WAF provides protection against common attacks and rate limiting - Origin-to-CloudFront traffic is unencrypted (HTTP-only constraint) - SSH access defaults to 0.0.0.0/0 in variables - **restrict in production** - CloudFront logs stored in S3 with 90-day lifecycle policy ### Performance Optimization - Price class set to PriceClass_100 (US, Canada, Europe) - Compression enabled for all content types - Custom error pages redirect 404/403 to index.html for SPA support ## CrowdSec Integration **🔄 Automated Workflow**: CrowdSec → API Gateway → Lambda → AWS WAF → CloudFront **📊 Current Resources (Updated 2025-09-09):** - **CloudFront Distribution ID**: `EATJ1HDQU8V51` - **CloudFront URL**: `https://d2mhxhntq3ezzr.cloudfront.net` - **WAF Web ACL ID**: `d61073b6-27b1-473e-aa9f-d2aa4a4c75a6` - **WAF IP Set ID**: `a9e47946-c186-4b28-83a8-fe3aeb9c296b` - **Deployment Status**: `Deployed` ✅ ### CrowdSec Integration Commands **⚠️ Note**: IP management is now automated via CrowdSec webhook integration. Manual commands are for monitoring and emergency use only. **View Current Blocked IPs:** ```bash # View current blocked IPs (Updated IP Set ID) aws wafv2 get-ip-set --scope CLOUDFRONT --region us-east-1 \ --id a9e47946-c186-4b28-83a8-fe3aeb9c296b \ --name aws-cf-dev-blocked-ips \ --query 'IPSet.Addresses' ``` **Test CrowdSec Webhook:** ```bash # Test webhook endpoint curl -X POST https://8zdmpjfnhh.execute-api.us-east-1.amazonaws.com/dev/webhook \ -H "Content-Type: application/json" \ -H "User-Agent: CrowdSec/1.7.0" \ -d '[{"uuid":"test","decisions":[{"value":"1.2.3.4","type":"ban","action":"add"}]}]' ``` **Monitor CrowdSec Container:** ```bash # Check CrowdSec status incus exec crowdsec -- cscli metrics # View current decisions incus exec crowdsec -- cscli decisions list # Test notifications incus exec crowdsec -- cscli notifications test aws-waf ``` **Lambda Function Monitoring:** ```bash # Check Lambda logs aws logs tail /aws/lambda/aws-cf-dev-crowdsec-waf-updater --follow # Test Lambda directly aws lambda invoke --function-name aws-cf-dev-crowdsec-waf-updater response.json ``` ### WAF Monitoring **Check WAF Metrics:** ```bash # Check blocked requests aws cloudwatch get-metric-statistics --namespace AWS/WAFV2 \ --metric-name BlockedRequests \ --dimensions Name=WebACL,Value=aws-cf-dev-waf Name=Rule,Value=BlockedIPsRule \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \ --period 300 --statistics Sum # Check rate limited requests aws cloudwatch get-metric-statistics --namespace AWS/WAFV2 \ --metric-name BlockedRequests \ --dimensions Name=WebACL,Value=aws-cf-dev-waf Name=Rule,Value=RateLimitRule \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \ --period 300 --statistics Sum ``` ## Working vs Disabled Features **Currently Working:** - CloudFront distribution with HTTP origin ✅ - WAF v2 with managed rules ✅ - S3 logging and state storage ✅ - Custom cache behaviors for API paths ✅ - IP-based blocking through WAF IP Sets ✅ **Currently Enabled:** - ACM custom certificates (b011e60a-1ea1-4dd3-844f-e0851ece4784) ✅ - Route53 DNS management (Z01934581JQAF2GS71GG) ✅ - WAF v2 with IP blocking (d61073b6-27b1-473e-aa9f-d2aa4a4c75a6) ✅ - CrowdSec webhook integration (setup required) ⚠️ **Currently Disabled (can be enabled with proper permissions):** - CloudFormation VPC stack (permission constraints) - DynamoDB state locking (permission constraints) ## WAF Troubleshooting History ### Issue Resolution (2025-09-09) **Problem**: WAF IP blocking was not functioning despite proper configuration. **Root Cause Analysis:** 1. **IP Set ID Mismatch**: Commands referenced old IP Set ID (`c43ff364-f3e2-43c7-8462-8fae20599d8d`) instead of actual ID 2. **CloudFront Deployment State**: Distribution was in "InProgress" status preventing WAF changes from taking effect 3. **Configuration Synchronization**: WAF and CloudFront association was not properly synchronized **Resolution Method:** - Complete infrastructure recreation using `tofu destroy` and `tofu apply` - All resources recreated with fresh IDs and proper associations - WAF rules now properly configured with correct IP Set references **Current Status:** - ✅ WAF properly associated with CloudFront (`EATJ1HDQU8V51`) - ✅ IP blocking rules functional (Priority 1: BlockedIPsRule) - ✅ Rate limiting active (10,000 requests/5min per IP) - ✅ AWS managed rule sets enabled (Common + Known Bad Inputs) - ✅ Test IP blocking verified: `1.2.3.4/32`, `61.77.18.91/32` **Key Commands for Manual IP Management:** ```bash # Add IP to blocked list aws wafv2 update-ip-set --scope=CLOUDFRONT --region=us-east-1 \ --id a9e47946-c186-4b28-83a8-fe3aeb9c296b \ --name aws-cf-dev-blocked-ips \ --addresses "IP1/32" "IP2/32" \ --lock-token $(aws wafv2 get-ip-set --scope=CLOUDFRONT --region=us-east-1 \ --id a9e47946-c186-4b28-83a8-fe3aeb9c296b \ --name aws-cf-dev-blocked-ips --query 'LockToken' --output text) # Verify WAF-CloudFront association aws cloudfront get-distribution --id EATJ1HDQU8V51 \ --query 'Distribution.DistributionConfig.WebACLId' --output text # Check current blocked IPs aws wafv2 get-ip-set --scope=CLOUDFRONT --region=us-east-1 \ --id a9e47946-c186-4b28-83a8-fe3aeb9c296b \ --name aws-cf-dev-blocked-ips --query 'IPSet.Addresses' ``` **Note**: WAF rule changes may take up to 15 minutes to propagate across CloudFront edge locations. # important-instruction-reminders Do what has been asked; nothing more, nothing less. NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.