Skip to main content

Overview

Aurora implements defense-in-depth security with multiple layers of protection:
  • Authentication & Authorization: User identity verification and access control
  • Secrets Management: HashiCorp Vault for sensitive credentials
  • Network Security: TLS encryption and CORS protection
  • Data Protection: Row-Level Security and encryption
  • Input Validation: Protection against injection attacks
  • Rate Limiting: DDoS and abuse prevention

Authentication

Password-Based Authentication

Aurora uses bcrypt for secure password hashing:
import bcrypt

# Registration
password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())

# Login
password_valid = bcrypt.checkpw(
    password.encode('utf-8'), 
    password_hash.encode('utf-8')
)
Security Features:
  • Minimum 8 characters password requirement
  • bcrypt hashing with automatic salt generation
  • Work factor: Default bcrypt cost parameter (10-12 rounds)
  • Constant-time comparison to prevent timing attacks
  • No password storage: Only hashed values stored in database
Best Practices:
# SECURE: Timing-attack resistant
if bcrypt.checkpw(user_password, stored_hash):
    return True

# INSECURE: Vulnerable to timing attacks
if user_password == stored_password:  # DON'T DO THIS
    return True

Session Management

Flask session cookies with secure configuration:
app.config.update(
    SECRET_KEY=os.getenv("FLASK_SECRET_KEY") or secrets.token_hex(24),
    SESSION_TYPE="filesystem",
    SESSION_PERMANENT=False,
    SESSION_FILE_DIR="/tmp/flask_session",
    SESSION_COOKIE_SECURE=True,      # HTTPS only in production
    SESSION_COOKIE_HTTPONLY=True,    # No JavaScript access
    SESSION_COOKIE_SAMESITE="Lax"    # CSRF protection
)
Session Security:
  • Secure cookies in production (HTTPS)
  • HttpOnly flag prevents XSS cookie theft
  • SameSite=Lax prevents CSRF attacks
  • File-based storage (not memory-based)
  • Automatic session cleanup

OAuth 2.0 Integration

Cloud provider authentication via OAuth: GCP OAuth Flow:
# 1. Generate authorization URL
auth_url = get_auth_url(state=user_id)

# 2. User authorizes in browser
# 3. Handle callback with authorization code
token_data = exchange_code_for_token(code)

# 4. Store tokens securely in Vault
store_tokens_in_db(user_id, token_data, "gcp")
OAuth Security:
  • State parameter prevents CSRF attacks
  • PKCE (optional) for public clients
  • Token encryption before storage
  • Automatic token refresh
  • Scope limitation (principle of least privilege)

Authorization

Row-Level Security (RLS)

PostgreSQL RLS enforces data isolation:
-- Enable RLS on table
ALTER TABLE chat_sessions ENABLE ROW LEVEL SECURITY;

-- Create user isolation policy
CREATE POLICY user_isolation_policy ON chat_sessions
    USING (user_id = current_setting('myapp.current_user_id', TRUE)::TEXT);
Protected Tables:
  • chat_sessions: Users can only access their own chats
  • incidents: Users can only see their incidents
  • user_tokens: Users can only access their credentials
  • llm_usage_tracking: Users can only see their usage
  • All Kubernetes and monitoring tables
Setting User Context:
with db_pool.get_admin_connection() as conn:
    cursor = conn.cursor()
    cursor.execute("SET myapp.current_user_id = %s", (user_id,))
    conn.commit()
    
    # Now queries respect RLS policies
    cursor.execute("SELECT * FROM chat_sessions")

API Authorization

Header-based authentication for API requests:
from utils.auth.stateless_auth import get_user_id_from_request

@app.route('/api/resource')
def get_resource():
    user_id = get_user_id_from_request()
    if not user_id:
        return jsonify({'error': 'Unauthorized'}), 401
    
    # User authenticated, proceed with request
    return jsonify({'data': ...})
Authentication Headers:
X-User-ID: user_abc123
Authorization: Bearer <token>  # For kubectl agent

Secrets Management

HashiCorp Vault

Aurora uses Vault for sensitive credential storage: Architecture:
┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Aurora    │────▶│  PostgreSQL  │────▶│    Vault    │
│   Server    │     │  (secret_ref)│     │  (secrets)  │
└─────────────┘     └──────────────┘     └─────────────┘
Configuration:
VAULT_ADDR=http://vault:8200
VAULT_TOKEN=hvs.xxxxxxxxxxxxx
VAULT_KV_MOUNT=aurora
VAULT_KV_BASE_PATH=
Storing Secrets:
from utils.secrets.vault_utils import store_secret_in_vault

# Store OAuth tokens in Vault
secret_ref = store_secret_in_vault(
    user_id=user_id,
    provider="gcp",
    data={
        "access_token": token_data["access_token"],
        "refresh_token": token_data["refresh_token"]
    }
)

# Store reference in database
cursor.execute(
    "UPDATE user_tokens SET secret_ref = %s WHERE user_id = %s AND provider = %s",
    (secret_ref, user_id, "gcp")
)
Retrieving Secrets:
from utils.secrets.vault_utils import get_secret_from_vault

# Get reference from database
cursor.execute(
    "SELECT secret_ref FROM user_tokens WHERE user_id = %s AND provider = %s",
    (user_id, "gcp")
)
secret_ref = cursor.fetchone()[0]

# Retrieve secret from Vault
token_data = get_secret_from_vault(secret_ref)
Secret References:
vault:kv/data/aurora/users/user_abc123/gcp

Redis Caching

Secrets cached in Redis with TTL:
from utils.secrets.secret_cache import get_cached_secret, cache_secret

# Check cache first
secret = get_cached_secret(secret_ref)
if not secret:
    # Cache miss, fetch from Vault
    secret = get_secret_from_vault(secret_ref)
    cache_secret(secret_ref, secret, ttl=3600)  # 1 hour TTL
Cache Invalidation:
from utils.secrets.secret_cache import clear_secret_cache

# Clear cache after credential update
clear_secret_cache(secret_ref)

Network Security

TLS/HTTPS

Production Configuration:
# nginx.conf
server {
    listen 443 ssl http2;
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    location / {
        proxy_pass http://aurora-server:5080;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

CORS Configuration

Cross-Origin Resource Sharing protection:
from flask_cors import CORS

CORS(app, 
    origins=FRONTEND_URL,
    supports_credentials=True,
    methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=[
        "Content-Type",
        "X-Provider",
        "X-User-ID",
        "Authorization"
    ]
)
Security Headers:
@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

Input Validation

SQL Injection Prevention

Always use parameterized queries:
# SECURE: Parameterized query
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (user_email,)
)

# INSECURE: String concatenation (NEVER DO THIS)
cursor.execute(
    f"SELECT * FROM users WHERE email = '{user_email}'"  # SQL INJECTION!
)

XSS Prevention

Frontend sanitization:
import DOMPurify from 'dompurify';

// Sanitize user input before rendering
const cleanHTML = DOMPurify.sanitize(userInput);
Backend validation:
import bleach

# Strip HTML tags from user input
clean_text = bleach.clean(user_input, tags=[], strip=True)

Command Injection Prevention

Never use shell=True with user input:
import subprocess

# SECURE: List arguments (no shell)
result = subprocess.run(
    ["kubectl", "get", "pods", "-n", namespace],
    capture_output=True,
    check=True
)

# INSECURE: shell=True with user input (COMMAND INJECTION!)
result = subprocess.run(
    f"kubectl get pods -n {namespace}",  # DANGEROUS!
    shell=True,
    capture_output=True
)

Path Traversal Prevention

Validate file paths:
import os

def safe_read_file(base_dir, filename):
    # Resolve absolute path
    filepath = os.path.abspath(os.path.join(base_dir, filename))
    
    # Ensure path is within base directory
    if not filepath.startswith(os.path.abspath(base_dir)):
        raise ValueError("Path traversal detected")
    
    with open(filepath, 'r') as f:
        return f.read()

Rate Limiting

API Rate Limiting

Protect against abuse and DDoS:
from utils.web.limiter_ext import limiter

# Global rate limit
limiter.init_app(app)

# Per-endpoint limits
@app.route('/api/resource')
@limiter.limit("100/minute")
def get_resource():
    return jsonify({'data': ...})

# Stricter limit for expensive operations
@app.route('/api/deploy')
@limiter.limit("10/minute")
def deploy():
    return jsonify({'status': 'deploying'})
Configuration:
app.config.update(
    RATELIMIT_STORAGE_URL="redis://redis:6379",
    RATELIMIT_STRATEGY="fixed-window",
    RATELIMIT_DEFAULT="100/minute"
)

WebSocket Rate Limiting

Custom rate limiter for WebSocket connections:
class RateLimiter:
    def __init__(self, rate, per):
        self.tokens = defaultdict(lambda: rate)
        self.rate = rate
        self.per = per
        self.last_checked = defaultdict(time.time)

    def is_allowed(self, client_id):
        now = time.time()
        elapsed = now - self.last_checked[client_id]
        self.last_checked[client_id] = now

        self.tokens[client_id] += elapsed * (self.rate / self.per)
        if self.tokens[client_id] > self.rate:
            self.tokens[client_id] = self.rate

        if self.tokens[client_id] >= 1:
            self.tokens[client_id] -= 1
            return True
        return False

# 5 messages per 60 seconds
rate_limiter = RateLimiter(rate=5, per=60)

Data Protection

Encryption at Rest

Database encryption:
# PostgreSQL with encryption
postgres:
  image: postgres:15
  command: postgres -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt
  volumes:
    - ./certs:/var/lib/postgresql
Object storage encryption:
from utils.storage.storage import get_storage_manager

storage = get_storage_manager(
    user_id=user_id,
    encryption=True  # Server-side encryption
)

storage.upload_file("sensitive-data.txt", data)

Encryption in Transit

All network traffic encrypted:
  • HTTPS for REST API (TLS 1.2+)
  • WSS for WebSocket (TLS 1.2+)
  • SSL for PostgreSQL connections
  • TLS for Redis connections

Data Retention

Soft deletes for user data:
-- Soft delete chat session
UPDATE chat_sessions 
SET is_active = false, updated_at = NOW()
WHERE id = %s AND user_id = %s;

-- Hard delete after retention period (30 days)
DELETE FROM chat_sessions 
WHERE is_active = false 
  AND updated_at < NOW() - INTERVAL '30 days';

Vulnerability Management

Dependency Scanning

Python dependencies:
# Scan for known vulnerabilities
pip-audit

# Update vulnerable packages
pip install --upgrade package-name
npm dependencies:
# Scan for vulnerabilities
npm audit

# Automatically fix
npm audit fix

Container Security

Dockerfile best practices:
# Use specific versions (not :latest)
FROM python:3.11-slim

# Run as non-root user
RUN useradd -m -u 1000 aurora
USER aurora

# Minimal base image
FROM python:3.11-slim AS base

# Multi-stage build
FROM base AS builder
# ... build steps ...

FROM base AS final
COPY --from=builder /app /app
Image scanning:
# Scan Docker images for vulnerabilities
trivy image aurora-server:latest

Incident Response

Logging

Security event logging:
import logging

logger = logging.getLogger(__name__)

# Log authentication events
logger.info(f"User logged in: {user_email}")
logger.warning(f"Failed login attempt: {user_email}")

# Log authorization failures
logger.error(f"Unauthorized access attempt: {user_id} -> {resource}")

# Log security-critical operations
logger.info(f"User {user_id} deleted incident {incident_id}")

Monitoring

Security metrics:
  • Failed authentication attempts
  • Rate limit violations
  • Unauthorized access attempts
  • Abnormal API usage patterns
  • Database connection failures

Reporting Security Issues

DO NOT report security vulnerabilities through public GitHub issues. Instead, email: [email protected] Include:
  • Type of vulnerability
  • Affected source files
  • Steps to reproduce
  • Proof-of-concept (if possible)
  • Impact assessment

Security Checklist

Development

  • All passwords hashed with bcrypt
  • Parameterized SQL queries only
  • No shell=True in subprocess calls
  • Input validation on all endpoints
  • Output sanitization for user-generated content
  • Secrets stored in Vault, not environment variables
  • Rate limiting on all public endpoints

Deployment

  • HTTPS enabled with valid certificates
  • Security headers configured
  • CORS properly restricted
  • Database encryption enabled
  • Redis password configured
  • Vault sealed/unsealed properly
  • Firewall rules configured
  • Container images scanned

Operations

  • Regular security updates applied
  • Dependency vulnerabilities patched
  • Audit logs reviewed regularly
  • Access logs monitored
  • Incident response plan documented
  • Backup encryption verified
  • Disaster recovery tested

Additional Resources

Build docs developers (and LLMs) love