Security Deployment Guide
Comprehensive guide for deploying Aragora securely in production environments.
Table of Contents
- Security Headers
- WAF Configuration
- TLS Configuration
- Network Security
- Secrets Management
- Monitoring and Alerting
- Application Security
Security Headers
Required Headers
Apply these headers to all responses in your reverse proxy (nginx, Cloudflare, etc.):
# nginx.conf
# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# Prevent clickjacking
add_header X-Frame-Options "DENY" always;
# Enable XSS filter (legacy browsers)
add_header X-XSS-Protection "1; mode=block" always;
# Enforce HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Control referrer information
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Restrict browser features
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" always;
Content Security Policy
Configure CSP based on your deployment:
# Production CSP - strict
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'unsafe-inline' https://js.stripe.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' wss://your-domain.com https://api.stripe.com;
frame-src https://js.stripe.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
" always;
CORS Headers
Configure CORS in your application or reverse proxy:
# Environment variable
ARAGORA_ALLOWED_ORIGINS=https://app.yourdomain.com,https://yourdomain.com
# nginx.conf
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Request-ID';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' '86400';
add_header 'Content-Length' '0';
return 204;
}
}
WAF Configuration
Cloudflare WAF
Recommended Cloudflare WAF rules for Aragora:
1. Rate Limiting Rules
Rule: API Rate Limit
Expression: (http.request.uri.path contains "/api/")
Action: Challenge
Rate: 100 requests per 10 seconds per IP
Rule: Auth Endpoint Protection
Expression: (http.request.uri.path contains "/api/auth/login" or http.request.uri.path contains "/api/auth/register")
Action: Challenge
Rate: 5 requests per minute per IP
2. SQL Injection Protection
Rule: SQL Injection Block
Expression: (
http.request.uri.query contains "UNION" or
http.request.uri.query contains "SELECT" or
http.request.uri.query contains "INSERT" or
http.request.uri.query contains "UPDATE" or
http.request.uri.query contains "DELETE" or
http.request.uri.query contains "--" or
http.request.uri.query contains "'" and http.request.uri.query contains "OR"
)
Action: Block
3. XSS Protection
Rule: XSS Block
Expression: (
http.request.uri.query contains "<script" or
http.request.uri.query contains "javascript:" or
http.request.uri.query contains "onerror=" or
http.request.uri.query contains "onload="
)
Action: Block
4. Path Traversal Protection
Rule: Path Traversal Block
Expression: (
http.request.uri.path contains ".." or
http.request.uri.path contains "..%2f" or
http.request.uri.path contains "%2e%2e"
)
Action: Block
5. Bot Protection
Rule: Known Bad Bots
Expression: (
cf.client.bot or
http.user_agent contains "sqlmap" or
http.user_agent contains "nikto" or
http.user_agent contains "nmap"
)
Action: Challenge
AWS WAF Rules
For AWS deployments, use these WAF rule sets:
# AWS WAF Web ACL
Resources:
AragoraWAF:
Type: AWS::WAFv2::WebACL
Properties:
Name: aragora-waf
Scope: REGIONAL
DefaultAction:
Allow: {}
Rules:
# AWS Managed Rule Sets
- Name: AWSManagedRulesCommonRuleSet
Priority: 1
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: CommonRuleSet
- Name: AWSManagedRulesKnownBadInputsRuleSet
Priority: 2
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesKnownBadInputsRuleSet
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: KnownBadInputsRuleSet
- Name: AWSManagedRulesSQLiRuleSet
Priority: 3
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesSQLiRuleSet
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: SQLiRuleSet
# Custom Rate Limiting
- Name: RateLimitRule
Priority: 4
Statement:
RateBasedStatement:
Limit: 2000
AggregateKeyType: IP
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RateLimitRule
nginx ModSecurity
For self-hosted deployments with nginx:
# /etc/nginx/modsecurity/aragora.conf
# Enable ModSecurity
SecRuleEngine On
# SQL Injection
SecRule ARGS|ARGS_NAMES|REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_BODY|REQUEST_HEADERS|XML:/*|XML://@* "@detectSQLi" \
"id:1,\
phase:2,\
block,\
capture,\
t:none,t:urlDecodeUni,\
msg:'SQL Injection Attack',\
logdata:'Matched Data: %{TX.0} found within %\{MATCHED_VAR_NAME\}',\
tag:'attack-sqli'"
# XSS
SecRule ARGS|ARGS_NAMES|REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_BODY|REQUEST_HEADERS|XML:/*|XML://@* "@detectXSS" \
"id:2,\
phase:2,\
block,\
capture,\
t:none,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,\
msg:'XSS Attack',\
logdata:'Matched Data: %{TX.0} found within %\{MATCHED_VAR_NAME\}',\
tag:'attack-xss'"
# Path Traversal
SecRule REQUEST_URI "@contains .." \
"id:3,\
phase:1,\
block,\
msg:'Path Traversal Attempt',\
tag:'attack-lfi'"
# Rate Limiting (use with nginx limit_req)
# See nginx rate limiting below
TLS Configuration
nginx TLS Configuration
# /etc/nginx/conf.d/ssl.conf
# TLS 1.2 and 1.3 only
ssl_protocols TLSv1.2 TLSv1.3;
# Strong cipher suites
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# SSL session caching
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# DH parameters (generate with: openssl dhparam -out /etc/nginx/dhparam.pem 2048)
ssl_dhparam /etc/nginx/dhparam.pem;
Certificate Requirements
- Use certificates from trusted CAs (Let's Encrypt, DigiCert, etc.)
- Enable automatic renewal
- Monitor certificate expiration
# Let's Encrypt with certbot
certbot certonly --nginx -d api.yourdomain.com -d app.yourdomain.com
# Auto-renewal cron
0 0 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
Network Security
Firewall Rules
# Allow HTTPS only
ufw allow 443/tcp
# Allow SSH from specific IPs
ufw allow from <admin-ip> to any port 22
# Block everything else
ufw default deny incoming
ufw enable
Internal Network Isolation
# kubernetes/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: aragora-network-policy
namespace: aragora
spec:
podSelector:
matchLabels:
app: aragora
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: nginx-ingress
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Allow external HTTPS for LLM APIs
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
Secrets Management
Environment Variables
Never commit secrets to version control.
# Production secrets (set in deployment platform)
ARAGORA_JWT_SECRET=<random-256-bit-key>
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
# Database credentials
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_KEY=eyJ...
Kubernetes Secrets
# secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: aragora-secrets
namespace: aragora
type: Opaque
stringData:
aragora-jwt-secret: $\{ARAGORA_JWT_SECRET\}
stripe-secret-key: $\{STRIPE_SECRET_KEY\}
anthropic-api-key: $\{ANTHROPIC_API_KEY\}
HashiCorp Vault
For advanced secret management:
# Example Vault integration
import hvac
client = hvac.Client(url='https://vault.internal:8200')
client.auth.kubernetes.login(role='aragora')
secrets = client.secrets.kv.read_secret_version(path='aragora/production')
ARAGORA_JWT_SECRET = secrets['data']['data']['aragora_jwt_secret']
Monitoring and Alerting
Security Alerts
Configure alerts for:
-
Authentication Failures
-
5 failed logins per user per hour
-
20 failed logins per IP per hour
-
-
Rate Limiting
-
100 requests blocked per minute
-
-
WAF Blocks
- Any SQL injection attempt
- Any XSS attempt
- Path traversal attempts
-
Certificate Expiration
- Alert at 30 days before expiry
- Critical at 7 days before expiry
Prometheus Alerts
# prometheus/alerts.yaml
groups:
- name: security
rules:
- alert: HighFailedLogins
expr: sum(rate(aragora_auth_failures_total[5m])) > 10
for: 5m
labels:
severity: warning
annotations:
summary: High rate of failed login attempts
- alert: WAFBlocksSpike
expr: sum(rate(aragora_waf_blocks_total[5m])) > 50
for: 2m
labels:
severity: critical
annotations:
summary: High rate of WAF blocks - possible attack
- alert: CertificateExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 7
for: 1h
labels:
severity: critical
annotations:
summary: TLS certificate expires in less than 7 days
Audit Logging
Enable comprehensive audit logging:
# Environment variable
ARAGORA_AUDIT_ENABLED=true
ARAGORA_AUDIT_RETENTION_DAYS=90
Audit log includes:
- All authentication events (login, logout, MFA)
- Authorization failures
- Admin actions
- Data access patterns
- API key usage
Application Security
Aragora includes several application-level security features that are enabled by default.
OIDC Token Validation
Token validation is enforced strictly in production mode:
# Environment variable (default: true in production)
ARAGORA_STRICT_TOKEN_VALIDATION=true
When enabled:
- ID tokens must have valid signatures (no fallback to userinfo endpoint)
- Expired tokens are rejected without exception
- Token claims (iss, aud, exp) are fully validated
Tenant Isolation
Multi-tenant deployments enforce strict resource isolation:
# Shared resources are validated at startup
# Only explicitly allowed resources can be shared across tenants:
ALLOWED_SHARED_RESOURCES = frozenset([
"system_agents", # System-provided agents
"public_templates", # Public workflow templates
])
Key protections:
- Query filters automatically include tenant_id
- Cross-tenant data access is logged and audited
- Shared resources are immutable and defined at startup
RBAC Permission Validation
All route permissions are validated at startup:
# Environment variable (default: false, set to true for strict mode)
ARAGORA_RBAC_STRICT_MODE=true
Features:
- Route permissions validated against SYSTEM_PERMISSIONS registry
- Undefined permissions logged as warnings (errors in strict mode)
- Wildcard permissions (e.g.,
admin.*) validated against defined permission prefixes - O(1) cache invalidation using version-based keys
Rate Limiting
Configure per-client and per-endpoint rate limits:
# Global rate limits
ARAGORA_RATE_LIMIT_REQUESTS=1000
ARAGORA_RATE_LIMIT_WINDOW_SECONDS=60
# Per-tier overrides
ARAGORA_RATE_LIMIT_FREE_TIER=100
ARAGORA_RATE_LIMIT_PRO_TIER=1000
ARAGORA_RATE_LIMIT_ENTERPRISE_TIER=10000
Security Checklist
Pre-Deployment
- All secrets stored in secure vault/platform secrets
- TLS certificates configured and valid
- WAF rules deployed and tested
- Security headers configured
- CORS properly restricted
- Rate limiting configured
- Network policies applied
- Audit logging enabled
Post-Deployment
- Penetration test completed
- Security monitoring active
- Alert thresholds configured
- Incident response plan documented
- Regular security updates scheduled
Periodic Review
- Review access logs monthly
- Rotate secrets quarterly
- Update dependencies weekly
- Review WAF rules quarterly
- Test backup restoration quarterly