Enterprise-Grade Web Application Firewall with Advanced Security Features
Built on Coraza v3 Engine | Real-Time Protection | Zero-Trust Architecture | GeoIP Blocking | Advanced Analytics
Features β’ Quick Start β’ Architecture β’ API β’ Deployment β’ Security
Obsidian Sentinel is an enterprise-ready Web Application Firewall that provides comprehensive protection against advanced cyber threats. It combines the battle-tested Coraza WAF engine with cutting-edge enterprise features including GeoIP blocking, advanced rate limiting, threat intelligence, webhook alerting, and sophisticated analytics.
| Feature | Description | |βββ|ββββ-| | 59+ Advanced WAF Rules | Protection against XSS, SQLi, RCE, LFI, RFI, SSRF, XXE, SSTI, LDAP injection | | JWT Authentication | HMAC-SHA256 signed tokens with configurable expiration and refresh | | Advanced RBAC | Role-based access control (Admin, Analyst, Viewer) with granular permissions | | 256-Shard Rate Limiting | High-performance sliding window with Redis clustering support | | Multi-Feed Threat Intel | Real-time protection from Spamhaus, Emerging Threats, Firehol (2000+ threats) | | GeoIP Blocking | Country-based protection with MaxMind database and risk scoring | | CSRF Protection | Token-based cross-site request forgery prevention | | Security Headers | CSP, HSTS, X-Frame-Options, X-Content-Type-Options |
| Feature | Description | |βββ|ββββ-| | PostgreSQL Integration | Enterprise-grade data persistence and analytics | | Redis Clustering | Distributed rate limiting and session management | | HIBP Password Checking | Real-time password breach validation using Have I Been Pwned | | Response Body DLP | Data Loss Prevention for sensitive information in HTTP responses | | GraphQL Security Analyzer | Advanced GraphQL query analysis with configurable limits | | Cache Statistics Dashboard | Real-time cache performance metrics and management | | Rate Limit Reset Controls | Administrative controls for rate limit management | | Glassmorphism UI | Modern dashboard with glassmorphism effects and enhanced UX | | Password Strength Meter | Real-time password validation with visual feedback | | Webhook Alerting | Real-time notifications to Slack, Teams, Discord, PagerDuty | | Executive Reporting | PDF/Excel reports with charts and threat analysis | | Comprehensive Audit | Complete security event trail with PostgreSQL storage | | WebSocket Real-Time | Live dashboard updates without polling overhead | | Advanced Analytics | Request patterns, geo-distribution, threat correlation | | Multi-Tenant Support | Admin, Security Analyst, and Read-Only Viewer roles | | Health & Metrics | Prometheus-compatible metrics and Kubernetes-ready health checks | | Request ID Tracing | End-to-end request tracking for incident response |
# Clone the repository
git clone https://github.com/Abhishek-yadav04/Obsidian.git
cd obsidian
# Install dependencies
go mod tidy
# Option 1: Run directly with Go (recommended for development)
go run ./cmd/obsidian
# Option 2: Build and run executable
cd cmd/obsidian
go build -o obsidian.exe .
./obsidian.exe
# Run with custom port
go run ./cmd/obsidian -port 8082
# Run in development mode with debug logging
go run ./cmd/obsidian -port 8082 -dev
# Run with PostgreSQL and Redis (Enterprise mode)
export DATABASE_URL="postgres://user:pass@localhost/obsidian"
export REDIS_URL="redis://localhost:6379"
export OBSIDIAN_JWT_SECRET="your-very-secure-jwt-secret-here-at-least-32-chars"
go run ./cmd/obsidian -port 8082
Open your browser and navigate to: http://localhost:8082
Default Credentials (CHANGE IMMEDIATELY IN PRODUCTION):
| Role | Username | Password |
|---|---|---|
| Admin | admin |
ObsidianAdmin#2024 |
| Analyst | analyst |
ObsidianAnalyst#2024 |
| Viewer | viewer |
ObsidianViewer#2024 |
Role Permissions:
π SECURITY NOTICE:
- Default passwords are documented and MUST be changed before production
- Set
OBSIDIAN_JWT_SECRETenvironment variable (min 32 characters)- Do NOT commit
.envfiles to version control
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client Request β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Security Headers Middleware β
β (CSP, X-Frame-Options, X-Content-Type-Options) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Rate Limiter Middleware β
β (Sliding Window, Per-IP Tracking) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Threat Intelligence Check β
β (Spamhaus DROP, Emerging Threats, Custom Lists) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Coraza WAF Engine β
β (55+ ModSecurity Rules) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Router β
β (API Handlers, Static Files) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
obsidian/
βββ cmd/obsidian/ # Main application entry point
β βββ main.go # Server initialization and routing
β βββ ui/ # Embedded frontend assets
β βββ index.html # Main dashboard (dark theme)
β βββ login.html # Authentication page
β βββ js/app.js # Frontend application logic
β βββ css/styles.css # Enterprise dark theme styling
β βββ assets/ # Static assets (logo, icons)
βββ internal/app/ # Core application packages
β βββ alerts/ # Webhook alert management
β βββ auth/ # JWT authentication & RBAC
β βββ geoip/ # Geographic IP blocking service
β βββ logging/ # Structured logging (Zap)
β βββ metrics/ # Prometheus-compatible metrics
β βββ ratelimit/ # 256-shard rate limiter
β βββ report/ # PDF/Excel report generation
β βββ security/ # Security middleware & headers
β βββ store/ # Data persistence (PostgreSQL/memory)
β βββ threatintel/ # Threat intelligence feeds
β βββ tracing/ # Request ID tracing
βββ migrations/ # Database migration scripts
β βββ 000001_initial_schema.up.sql
β βββ 000001_initial_schema.down.sql
βββ configs/ # Configuration files
β βββ config.yaml # Default configuration
βββ testing/ # Test suites and benchmarks
βββ e2e/ # End-to-end integration tests
βββ performance/ # Load testing scenarios
βββ testdata/ # Test fixtures and data
| Variable | Description | Default | Required |
|---|---|---|---|
OBSIDIAN_JWT_SECRET |
JWT signing secret (min 32 chars) | Random in dev | Yes (prod) |
OBSIDIAN_ENV |
Environment (development/production) | development | No |
OBSIDIAN_ALLOWED_ORIGINS |
Comma-separated WebSocket origins | localhost:8082 | No |
DATABASE_URL |
PostgreSQL connection string | None | Yes |
REDIS_URL |
Redis connection string | None | No |
GEOIP_DATABASE_PATH |
Path to MaxMind GeoIP2 database | None | No |
SUPABASE_URL |
Supabase project URL for OAuth | None | No (for OAuth) |
SUPABASE_KEY |
Supabase anon/public key | None | No (for OAuth) |
LOG_LEVEL |
Logging level (debug, info, warn, error) | info | No |
LOG_FORMAT |
Log format (json, console) | json | No |
OBSIDIAN_CRS_ENABLED |
Enable OWASP CRS loading | false | No |
OBSIDIAN_CRS_PATH |
Filesystem path to CRS root | None | No |
OBSIDIAN_CRS_MODE |
CRS engine mode (DetectionOnly/On) | DetectionOnly | No |
OBSIDIAN_CRS_FAIL_OPEN |
Continue startup if CRS load fails | false | No |
OBSIDIAN_WAF_CUSTOM_RULES |
Path to Obsidian custom rules file | rules/obsidian-custom.conf | No |
Obsidian loads OWASP CRS as an external ruleset at runtime. CRS files are not vendored in this repository. To enable CRS, place the official CRS files on disk and point OBSIDIAN_CRS_PATH to the CRS root that contains crs-setup.conf and the rules/ directory.
./obsidian.exe [options]
Options:
-port int Port to run the server on (default 8082)
-dev Run in development mode (relaxed security)
-log-level Override LOG_LEVEL env var
-log-format Override LOG_FORMAT env var
# β οΈ NEVER COMMIT THIS FILE TO VERSION CONTROL
# Copy to .env and customize for your environment
# JWT Authentication (REQUIRED in production - min 32 chars)
OBSIDIAN_JWT_SECRET=your-super-secure-random-secret-minimum-32-chars
# Environment
OBSIDIAN_ENV=production
# PostgreSQL Database (REQUIRED)
DATABASE_URL=postgresql://obsidian:secure_password@localhost:5432/obsidian?sslmode=require
# Redis Cache (OPTIONAL - enables distributed rate limiting)
REDIS_URL=redis://localhost:6379/0
# For TLS: REDIS_URL=rediss://user:pass@host:port/0
# OAuth via Supabase (OPTIONAL - enables Google/GitHub login)
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-anon-public-key
# WebSocket Origins (customize for your domain)
OBSIDIAN_ALLOWED_ORIGINS=https://your-domain.com
# GeoIP Database (OPTIONAL)
GEOIP_DATABASE_PATH=/opt/maxmind/GeoLite2-Country.mmdb
# Logging
LOG_LEVEL=info
LOG_FORMAT=json
# OWASP CRS (external ruleset)
OBSIDIAN_CRS_ENABLED=false
OBSIDIAN_CRS_PATH=/opt/owasp-crs
OBSIDIAN_CRS_MODE=DetectionOnly
OBSIDIAN_CRS_FAIL_OPEN=false
OBSIDIAN_WAF_CUSTOM_RULES=rules/obsidian-custom.conf
OBSIDIAN_JWT_SECRET (32+ random characters)OBSIDIAN_ENV=productionsslmode=require)OBSIDIAN_ALLOWED_ORIGINSAuthenticate and receive JWT token.
Request:
{
"username": "admin",
"password": "password"
}
Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "...",
"user": {
"id": 1,
"username": "admin",
"role": "Admin"
},
"expires_in": 900
}
| Endpoint | Method | Description | Required Role |
|βββ-|βββ|ββββ-|βββββ|
| /api/stats | GET | Dashboard statistics with geo data | Viewer |
| /api/logs | GET | Security event logs with pagination | Viewer |
| /api/rules | GET | WAF rules list (59 rules) | Viewer |
| /api/rules/create | POST | Create new WAF rule | Admin |
| /api/rules/update | PUT | Update existing rule | Admin |
| /api/rules/delete | DELETE | Delete rule by ID | Admin |
| /api/threats | GET | Threat intelligence data (2000+ threats) | Viewer |
| /api/threats/block | POST | Block IP address | Admin |
| Endpoint | Method | Description | Required Role |
|βββ-|βββ|ββββ-|βββββ|
| /api/metrics | GET | System and security metrics | Viewer |
| /api/geoip/lookup | GET | GeoIP lookup for any IP | Viewer |
| /api/geoip/blocked | GET/POST/DELETE | Manage blocked countries | Admin |
| /api/geoip/metrics | GET | GeoIP service statistics | Viewer |
| /api/ratelimit/blacklist | POST/DELETE | Manage IP blacklist | Admin |
| /api/ratelimit/whitelist | POST/DELETE | Manage IP whitelist | Admin |
| Endpoint | Method | Description | Required Role |
|βββ-|βββ|ββββ-|βββββ|
| /api/alerts/webhooks | GET/POST/DELETE | Manage webhook integrations | Admin |
| /api/alerts/webhooks/test | POST | Test webhook configuration | Admin |
| /api/export | GET | Export security reports (PDF/Excel) | Analyst |
| /api/admin/users | GET | User management | Admin |
| /api/admin/audit | GET | Comprehensive audit logs | Admin |
Returns comprehensive system health status.
βnoteβ: βSee CI / Release section in this README for how releases are built and how to pull the official Docker image from GHCR.β
---
## π§© CI / Release
Releases are performed by the repository GitHub Actions workflows. Key points:
- The CI pipeline builds and tests the project, runs linting, security scans, and produces artifacts (platform binaries).
- A separate Docker job builds multi-arch images and pushes them to GitHub Container Registry (GHCR) under `ghcr.io/<owner>/<repo>:<tag>`.
- The release job packages artifacts and creates a GitHub Release. The workflow also verifies the pushed Docker image by attempting to `docker pull` the released image during the release job.
- An SBOM (CycloneDX JSON) is generated and attached to the release artifacts.
How to pull the official release image from GHCR:
```bash
# Authenticate to GHCR (use a personal access token with appropriate scopes)
echo "${GHCR_TOKEN}" | docker login ghcr.io -u <USERNAME> --password-stdin
# Pull the image for a given tag (example: v2.2.4)
docker pull ghcr.io/<owner>/<repo>:v2.2.4
If you run into problems with releases or CI, check .github/workflows/ci.yml and .github/workflows/release.yml for the exact steps executed during builds.
{ βstatusβ: βhealthyβ, βuptimeβ: β2h30m15sβ, βversionβ: β2.1.0β, βeditionβ: βEnterpriseβ, βnameβ: βObsidian Sentinel WAFβ, βfeaturesβ: { βwaf_engineβ: true, βthreat_intelligenceβ: true, βrate_limitingβ: true, βgeoip_blockingβ: true, βwebhook_alertsβ: true, βpostgresqlβ: true, βredisβ: true, βadvanced_analyticsβ: true }, βstatsβ: { βtotal_requestsβ: 15432, βblocked_requestsβ: 127, βactive_threatsβ: 2041, βblocked_countriesβ: 3 } }
---
## π Security
### JWT Token Security
- Tokens signed with HMAC-SHA256
- Configurable expiration (default: 15 minutes)
- Refresh token rotation
- Secrets stored in environment variables
- Constant-time signature comparison
- Role-based claims validation
### Advanced Rate Limiting
- 256-shard sliding window algorithm
- Redis-backed distributed limiting
- Per-IP and per-endpoint tracking
- Configurable limits:
- 200 requests/minute general
- 5 login attempts/minute
- Custom thresholds per endpoint
- Whitelist/blacklist IP management
- Geographic rate limiting
### Threat Intelligence Sources
- **Spamhaus DROP/EDROP** - 800+ malicious networks
- **Emerging Threats** - 1000+ compromised IPs
- **Firehol Level 1** - 200+ high-confidence threats
- **Custom feeds** - User-defined blocklists
- **GeoIP risk scoring** - Country-based threat assessment
- **Real-time updates** - Feeds refreshed every 4 hours
### GeoIP Security
- MaxMind GeoIP2 database integration
- Country-based blocking/allowing
- Risk score calculation
- VPN/Proxy/Tor detection
- Threat score based on geography
- Custom country rules with reasons
### Security Headers
X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Content-Security-Policy: default-src βselfβ; β¦
---
## π¦ Deployment
### Docker (Recommended)
#### Simple Deployment
```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN cd cmd/obsidian && go build -o obsidian .
FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /app
COPY --from=builder /app/cmd/obsidian/obsidian .
EXPOSE 8082
CMD ["./obsidian", "-port", "8082"]
Use the checked-in docker-compose.yml and one of these env templates:
.env.docker.example for local postgres + redis containers.env.external.example for managed/external DB + Redis# Internal postgres + redis
cp .env.docker.example .env.docker
docker compose --env-file .env.docker up -d --build
# External managed services
cp .env.external.example .env.external
docker compose --env-file .env.external up -d --build
Notes:
postgres, redis) in URLs, not localhost..env is for local go run workflows; prefer dedicated env files for Docker publish/deploy.OBSIDIAN_JWT_SECRET is required and must be set per environment.apiVersion: apps/v1
kind: Deployment
metadata:
name: obsidian-waf
namespace: security
spec:
replicas: 3
selector:
matchLabels:
app: obsidian-waf
template:
metadata:
labels:
app: obsidian-waf
spec:
containers:
- name: obsidian
image: obsidian:2.1.0
ports:
- containerPort: 8082
env:
- name: OBSIDIAN_JWT_SECRET
valueFrom:
secretKeyRef:
name: obsidian-secrets
key: jwt-secret
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: obsidian-secrets
key: database-url
- name: REDIS_URL
value: "redis://obsidian-redis:6379/0"
- name: GEOIP_DATABASE_PATH
value: "/data/GeoLite2-Country.mmdb"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /api/health
port: 8082
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /api/health
port: 8082
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: geoip-data
mountPath: /data
volumes:
- name: geoip-data
configMap:
name: geoip-database
---
apiVersion: v1
kind: Service
metadata:
name: obsidian-waf-service
spec:
selector:
app: obsidian-waf
ports:
- protocol: TCP
port: 80
targetPort: 8082
type: LoadBalancer
[Unit]
Description=Obsidian Sentinel WAF
After=network.target
[Service]
Type=simple
User=obsidian
WorkingDirectory=/opt/obsidian
Environment=OBSIDIAN_JWT_SECRET=your-secret-here
ExecStart=/opt/obsidian/obsidian -port 8082
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
| Document | Description |
|---|---|
| Production Audit Report | Comprehensive security audit with 100 issues and 50 features |
| Contributing Guide | How to contribute to the project |
| Security Policy | How to report vulnerabilities |
| License | Apache 2.0 License |
go test ./... -v
go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
# Test XSS blocking
curl -X GET "http://localhost:8082/api/test?input=<script>alert(1)</script>"
# Test SQL injection blocking
curl -X GET "http://localhost:8082/api/test?id=1' OR '1'='1"
GET /api/metrics returns comprehensive system metrics:
{
"total_requests": 25432,
"blocked_requests": 327,
"uptime_seconds": 172800,
"memory_alloc_mb": 65,
"memory_sys_mb": 128,
"goroutines": 23,
"rate_limiter": {
"active_visitors": 15,
"blacklist_count": 5,
"whitelist_count": 10,
"rate_limited_ips": 3,
"requests_per_minute": 200,
"shards": 256,
"total_allowed": 25105,
"total_blocked": 327
},
"threat_intel": {
"total_threats": 2041,
"feeds_active": 4,
"last_update": "2026-02-01T14:30:00Z",
"blocked_today": 127,
"high_risk_count": 1205
},
"geoip": {
"blocked_countries": 3,
"total_lookups": 15432,
"cache_hits": 12890,
"cache_misses": 2542
},
"webhooks": {
"active_webhooks": 2,
"alerts_sent_today": 15,
"alerts_failed": 1
}
}
Connect to ws://localhost:8082/api/ws?token=<jwt> for live stats updates.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)See CONTRIBUTING.md for detailed guidelines.
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
Abhishek Yadav
Computer Science Student
β Star this repo if you find it helpful!
Made with β€οΈ for the cybersecurity community
First and foremost, huge thanks to Juan Pablo Tosso for starting this project, and building an amazing community around Coraza!
Today we have lots of amazing contributors, we could not have done this without you!
Made with contrib.rocks.