- Update all resource IDs to match current deployment - CloudFront Distribution: EATJ1HDQU8V51 - WAF Web ACL: d61073b6-27b1-473e-aa9f-d2aa4a4c75a6 - WAF IP Set: a9e47946-c186-4b28-83a8-fe3aeb9c296b - ACM Certificate: b011e60a-1ea1-4dd3-844f-e0851ece4784 - Route53 Zone: Z01934581JQAF2GS71GG - Reflect enabled ACM certificate and Route53 DNS management - Update all AWS CLI commands with correct resource IDs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
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
# Initialize OpenTofu (required after cloning)
tofu init
# Plan changes
tofu plan
# Apply changes
tofu apply
# Destroy infrastructure
tofu destroy
Backend Setup (S3 + CloudFront Logs)
# 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
# Validate configuration
tofu validate
# Format files
tofu fmt
# Check syntax and validate variables
tofu plan -var-file=terraform.tfvars
AWS Resource Verification
# 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 behaviorssecurity.tf- WAF Web ACL with rate limiting, managed rule sets, and security groupslambda.tf- CrowdSec Lambda integration with API Gatewaylambda-crowdsec-waf.py- Lambda function for real-time IP managementvariables.tf- All configurable parameters with validation rulesoutputs.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 constraintsacm.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_nameandenvironmentenable 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 domainenable_waf = true- WAF is working and provides important securitycreate_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:
# 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:
# 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:
# 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:
# 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:
# 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:
- IP Set ID Mismatch: Commands referenced old IP Set ID (
c43ff364-f3e2-43c7-8462-8fae20599d8d) instead of actual ID - CloudFront Deployment State: Distribution was in "InProgress" status preventing WAF changes from taking effect
- Configuration Synchronization: WAF and CloudFront association was not properly synchronized
Resolution Method:
- Complete infrastructure recreation using
tofu destroyandtofu 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:
# 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.