diff --git a/Caddyfile b/Caddyfile index b71030c..e30dddc 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,5 +1,4 @@ { - # Global options order coraza_waf first } @@ -9,25 +8,30 @@ respond "WAF-UI-OK" 200 } + # Handle WebSocket paths without WAF + handle /ws/* { + reverse_proxy localhost:9001 { + header_up Host {http.request.host} + header_up X-Real-IP {remote} + header_up X-Forwarded-For {remote} + header_up X-Forwarded-Proto {scheme} + header_up Connection {http.request.header.connection} + header_up Upgrade {http.request.header.upgrade} + header_up Sec-WebSocket-Key {http.request.header.sec-websocket-key} + header_up Sec-WebSocket-Version {http.request.header.sec-websocket-version} + transport http { + read_timeout 300s + dial_timeout 300s + } + } + } + route { coraza_waf { - load_owasp_crs - + load_owasp_crs directives ` - # Step 1: Initialize TX collection SecAction "id:1,phase:1,pass,nolog,initcol:tx=tx" - - # Step 2: Initialize TX variable SecAction "id:2,phase:1,pass,nolog,setvar:tx.bucket_ops=0" - - # Allow WebSocket connections for MinIO console - SecRule REQUEST_HEADERS:Upgrade "@streq websocket" "id:1001,phase:1,pass,msg:'Allow WebSocket upgrade requests'" - - # Block DELETE on /minio/admin (except WebSocket connections) - SecRule REQUEST_URI "@beginsWith /minio/admin" "id:1002,phase:1,deny,status:403,msg:'MinIO Admin API Access Blocked',chain" - SecRule REQUEST_HEADERS:Upgrade "!@streq websocket" - - # Rate limiting SecRule REQUEST_METHOD "@rx ^(PUT|POST|DELETE)$" "id:1003,phase:1,pass,msg:'Bucket operation',setvar:tx.bucket_ops=+1,expirevar:tx.bucket_ops=60" SecRule TX:bucket_ops "@gt 50" "id:1004,phase:1,deny,status:429,msg:'Bucket operation rate limit exceeded'" ` @@ -38,7 +42,6 @@ header_up X-Real-IP {remote} header_up X-Forwarded-For {remote} header_up X-Forwarded-Proto {scheme} - header_up Connection {http.request.header.connection} header_up Upgrade {http.request.header.upgrade} header_up Sec-WebSocket-Key {http.request.header.sec-websocket-key} @@ -65,19 +68,11 @@ route { coraza_waf { - load_owasp_crs - + load_owasp_crs directives ` - # Step 1: Initialize TX collection SecAction "id:10,phase:1,pass,nolog,initcol:tx=tx" - - # Step 2: Initialize TX variable SecAction "id:11,phase:1,pass,nolog,setvar:tx.bucket_ops=0" - - # Log DELETE operations SecRule REQUEST_METHOD "@streq DELETE" "id:2001,phase:1,log,msg:'DELETE operation logged'" - - # Rate limiting SecRule REQUEST_METHOD "@rx ^(PUT|POST|DELETE)$" "id:2002,phase:1,pass,msg:'Bucket operation',setvar:tx.bucket_ops=+1,expirevar:tx.bucket_ops=60" SecRule TX:bucket_ops "@gt 50" "id:2003,phase:1,deny,status:429,msg:'Bucket operation rate limit exceeded'" ` @@ -86,7 +81,6 @@ reverse_proxy localhost:9000 { header_up Connection {http.request.header.connection} header_up Upgrade {http.request.header.upgrade} - } } diff --git a/README-coraza.md b/README-coraza.md index e7e9ca5..2dc8bc3 100644 --- a/README-coraza.md +++ b/README-coraza.md @@ -6,7 +6,6 @@ A modern Web Application Firewall built with [Coraza](https://coraza.io) and [Ca - ✅ **OWASP Core Rule Set v4** - Latest security rules - ✅ **Multi-backend routing** - Single WAF protects MinIO UI + API -- ✅ **Automatic HTTPS** - TLS termination included - ✅ **Security headers** - Production-ready security configuration - ✅ **Health checks** - Built-in monitoring endpoints - ✅ **Rate limiting** - API protection against abuse @@ -45,8 +44,8 @@ docker run -d \ ## Architecture ``` -Internet → Caddy WAF (8443) → MinIO UI (9001) - → MinIO API (9000) +Caddy WAF (8080) → MinIO UI (9001) + (8081) → MinIO API (9000) ``` ### Request Routing @@ -66,7 +65,6 @@ Internet → Caddy WAF (8443) → MinIO UI (9001) - Rate limiting (100 req/min per IP for API endpoints) ### Custom MinIO Rules -- Blocks access to `/minio/admin` endpoints - Logs all DELETE operations for audit - Rate limits API endpoints diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a076bf7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +version: '3.8' +services: + minio: + image: quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z + container_name: minio + command: server /data --console-address ":9001" --address ":9000" + environment: + - MINIO_ROOT_USER=minioadmin + - MINIO_ROOT_PASSWORD=your-password + ports: + - "9000:9000" + - "9001:9001" + volumes: + - minio-data:/data + networks: + - minio-net + + coraza-waf: + image: coraza-waf-local:latest + container_name: coraza-waf + ports: + - "8080:8080" + - "8081:8081" + depends_on: + - minio + networks: + - minio-net + +volumes: + minio-data: + +networks: + minio-net: + driver: bridge diff --git a/main.tf b/main.tf index e6cdbcc..e9d23d5 100644 --- a/main.tf +++ b/main.tf @@ -465,5 +465,18 @@ resource "azurerm_container_group" "minio_aci_container_group" { timeout_seconds = 3 failure_threshold = 3 } + # The Caddyfile is included as part of the container build. + # If you are testing or want to use a different configuration, you can provide your own + # volume { + # name = "caddyfile" + # mount_path = "/etc/caddy" + # read_only = true + + # secret = { + # "Caddyfile" = base64encode(templatefile("${path.module}/Caddyfile.working.tpl", { + # })) + # } + # } + } }