# Flowfish - Security Design ## πŸ”’ Overview Flowfish platform security is designed according to Defense in Depth (layered defense) principles. --- ## 🎯 Security Principles 1. **Least Privilege**: Minimum necessary privileges 2. **Defense in Depth**: Multi-layered security 3. **Zero Trust**: Verify every request 4. **Encryption**: Data encryption (at-rest & in-transit) 5. **Audit**: Log all operations 6. **Isolation**: Multi-tenant isolation --- ## πŸ” Authentication ### 1. JWT Token Authentication **Token Structure**: ```json { "header": { "alg": "HS256", "typ": "JWT" }, "payload": { "user_id": 123, "username": "admin", "roles": ["Super Admin"], "exp": 1704067200, "iat": 1704063600 } } ``` **Token Lifecycle**: - **Access Token**: 1 hour (short-lived) - **Refresh Token**: 7 days (long-lived) - **Storage**: HttpOnly cookie (XSS protection) - **Transmission**: Authorization header **Token Generation**: ```python import jwt from datetime import datetime, timedelta def create_access_token(user_id, username, roles): payload = { 'user_id': user_id, 'username': username, 'roles': roles, 'exp': datetime.utcnow() + timedelta(hours=1), 'iat': datetime.utcnow() } return jwt.encode(payload, SECRET_KEY, algorithm='HS256') ``` **Token Validation**: - Signature verification - Expiration check - Blacklist check (Redis) - Role/permission check ### 2. OAuth 2.0 / SSO **Supported Providers**: - Google Workspace - Microsoft Azure AD / Entra ID - Okta - Keycloak **OAuth Flow** (Authorization Code): ``` User β†’ Login Button β†’ Flowfish Frontend β†’ Redirect to OAuth Provider β†’ User authenticates β†’ Provider redirects with auth code β†’ Flowfish exchanges code for token β†’ Create/update user in database β†’ Issue JWT token β†’ Redirect to dashboard ``` **Security Controls**: - State parameter (CSRF protection) - PKCE (Proof Key for Code Exchange) - Token validation - User account linking ### 3. Kubernetes Service Account **In-Cluster Authentication**: ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: flowfish-backend namespace: flowfish --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: flowfish-reader rules: - apiGroups: [""] resources: ["pods", "services", "namespaces"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: flowfish-reader-binding subjects: - kind: ServiceAccount name: flowfish-backend namespace: flowfish roleRef: kind: ClusterRole name: flowfish-reader apiGroup: rbac.authorization.k8s.io ``` --- ## πŸ‘₯ Authorization ### RBAC (Role-Based Access Control) **Role Hierarchy**: ``` Super Admin (ALL permissions) └─ Platform Admin (Management + Analysis) └─ Security Analyst (Security + Read) └─ Developer (Read-only) ``` **Permission Model**: ``` Permission = Resource + Action Example: clusters.view, analyses.execute, users.delete ``` **Permission Matrix**: | Resource | Super Admin | Platform Admin | Security Analyst | Developer | |----------|-------------|----------------|------------------|-----------| | clusters.* | βœ… | βœ… | ❌ | ❌ | | analyses.* | βœ… | βœ… | ❌ | ❌ | | dependencies.view | βœ… | βœ… | βœ… | βœ… | | anomalies.* | βœ… | βœ… | βœ… | ❌ | | users.* | βœ… | ❌ | ❌ | ❌ | | audit.view | βœ… | βœ… | βœ… | ❌ | **Middleware Implementation**: ```python async def require_permission(permission: str): def decorator(func): @wraps(func) async def wrapper(request: Request, *args, **kwargs): user = request.state.user if not has_permission(user, permission): raise HTTPException(403, "Insufficient permissions") return await func(request, *args, **kwargs) return wrapper return decorator @app.get("/api/v1/clusters") @require_permission("clusters.view") async def get_clusters(): ... ``` ### Multi-Tenant Isolation **Tenant Separation**: - **Cluster-level**: Users can only access assigned clusters - **Namespace-level**: Namespace-based access control - **Data-level**: SQL WHERE clauses filter by user **Row-Level Security** (PostgreSQL): ```sql -- Enable RLS ALTER TABLE workloads ENABLE ROW LEVEL SECURITY; -- Policy: Users can only see workloads from their clusters CREATE POLICY workload_isolation ON workloads FOR SELECT USING (cluster_id IN ( SELECT cluster_id FROM user_cluster_access WHERE user_id = current_user_id() )); ``` --- ## πŸ”’ Data Encryption ### 1. At-Rest Encryption **Database Encryption**: **PostgreSQL**: ```bash # Transparent Data Encryption (TDE) # Using encrypted volumes or PostgreSQL 15+ TDE pgcrypto extension for column-level encryption ``` **Encryption Example**: ```sql -- Encrypt sensitive fields CREATE TABLE oauth_providers ( id SERIAL PRIMARY KEY, client_secret_encrypted TEXT NOT NULL, ... ); -- Encrypt on insert INSERT INTO oauth_providers (client_secret_encrypted) VALUES (pgp_sym_encrypt('secret_value', 'encryption_key')); -- Decrypt on select SELECT pgp_sym_decrypt(client_secret_encrypted::bytea, 'encryption_key') FROM oauth_providers; ``` **ClickHouse**: - Disk encryption via OS (LUKS) - Column-level encryption (optional) **Neo4j**: - Volume encryption via Kubernetes PVC **Redis**: - Volume encryption - No built-in encryption **Key Management**: - **Development**: Environment variables - **Production**: Kubernetes Secrets + External Secrets Operator - **Enterprise**: HashiCorp Vault, AWS KMS, Azure Key Vault ### 2. In-Transit Encryption **TLS/SSL Everywhere**: **Frontend ↔ User**: ``` HTTPS (TLS 1.3) - Certificate: Let's Encrypt or corporate CA - Strong ciphers only - HSTS header enabled ``` **Frontend ↔ Backend**: ``` HTTPS (TLS 1.2+) - Internal service mesh (optional: mTLS via Istio) - Certificate rotation ``` **Backend ↔ Databases**: **PostgreSQL**: ```python # Connection string with SSL DATABASE_URL = "postgresql://user:pass@host:5432/db?sslmode=require" ``` **ClickHouse**: ```xml 8443 /etc/clickhouse-server/server.crt /etc/clickhouse-server/server.key ``` **Neo4j**: ```yaml # SSL enabled connection ssl: enable: true cert_path: /path/to/cert.pem key_path: /path/to/key.pem ``` --- ## πŸ›‘οΈ Application Security ### 1. Input Validation **Backend Validation** (Pydantic): ```python from pydantic import BaseModel, validator, constr class ClusterCreate(BaseModel): name: constr(min_length=3, max_length=255) api_url: HttpUrl @validator('name') def validate_name(cls, v): if not re.match(r'^[a-z0-9-]+$', v): raise ValueError('Name must be lowercase alphanumeric with hyphens') return v ``` **SQL Injection Prevention**: ```python # βœ… Good: Parameterized query cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) # ❌ Bad: String concatenation cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") ``` ### 2. XSS Prevention **React**: - Default XSS protection (JSX escaping) - DangerouslySetInnerHTML avoided **Content Security Policy**: ```http Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' wss:; frame-ancestors 'none'; ``` ### 3. CSRF Protection **SameSite Cookies**: ```python response.set_cookie( key="refresh_token", value=token, httponly=True, secure=True, samesite="strict" ) ``` **CSRF Token**: ```python # Generate token csrf_token = secrets.token_urlsafe(32) session['csrf_token'] = csrf_token # Validate token if request.form['csrf_token'] != session['csrf_token']: raise HTTPException(403, "CSRF token mismatch") ``` ### 4. Rate Limiting **API Rate Limiting**: ```python from slowapi import Limiter from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address) @app.get("/api/v1/clusters") @limiter.limit("100/hour") async def get_clusters(): ... ``` **Redis-based Rate Limiting**: ```python def check_rate_limit(user_id, limit=100, window=3600): key = f"rate_limit:{user_id}" current = redis.incr(key) if current == 1: redis.expire(key, window) if current > limit: raise HTTPException(429, "Rate limit exceeded") ``` --- ## πŸ” Kubernetes Security ### 1. Network Policies **Default Deny**: ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: flowfish spec: podSelector: {} policyTypes: - Ingress - Egress ``` **Allow Backend β†’ Database**: ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-to-postgres namespace: flowfish spec: podSelector: matchLabels: app: postgresql policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: backend ports: - protocol: TCP port: 5432 ``` ### 2. Pod Security **Pod Security Standards**: ```yaml apiVersion: v1 kind: Pod metadata: name: backend spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: backend image: flowfish/backend:latest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: limits: memory: "4Gi" cpu: "2000m" requests: memory: "1Gi" cpu: "500m" ``` ### 3. Secrets Management **Kubernetes Secrets**: ```yaml apiVersion: v1 kind: Secret metadata: name: database-credentials namespace: flowfish type: Opaque stringData: username: flowfish_user password: ``` **External Secrets Operator**: ```yaml apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-backend namespace: flowfish spec: provider: vault: server: "https://vault.example.com" path: "secret" auth: kubernetes: mountPath: "kubernetes" role: "flowfish" --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: database-secret namespace: flowfish spec: refreshInterval: 15m secretStoreRef: name: vault-backend kind: SecretStore target: name: database-credentials data: - secretKey: password remoteRef: key: database/credentials property: password ``` --- ## πŸ“ Audit Logging ### Comprehensive Logging **Log Everything**: - User login/logout - API requests (method, path, user, IP) - Database changes (CREATE, UPDATE, DELETE) - Permission changes - Configuration changes - Anomaly detections - Import/export operations **Log Format** (JSON): ```json { "timestamp": "2024-01-15T10:30:45.123Z", "level": "INFO", "user_id": 123, "username": "admin", "action": "create_cluster", "resource_type": "cluster", "resource_id": "cluster-prod-01", "ip_address": "10.0.1.50", "user_agent": "Mozilla/5.0...", "request_id": "abc-def-123", "success": true, "details": {...} } ``` Fixing a typo introduced in `06-security.md` JSON. <|tool▁calls▁begin|><|tool▁call▁begin|> StrReplace