Skip to main content

Overview

NeoSC is built with a Zero Trust architecture integrating Zitadel OIDC for authentication, Pomerium for access control, and NetBird for encrypted networking. This guide covers security hardening, MFA implementation, and policy enforcement.

Zero Trust Architecture

NeoSC implements Zero Trust principles:

Network Layer (NetBird)

  • WireGuard Encryption: All workspace connections use encrypted tunnels
  • No Open Ports: Direct connections blocked, all traffic through authenticated tunnels
  • Peer-to-Peer: Direct encrypted connections between clients and resources
# From infra/docker-compose.yml:19-26
networks:
  proxy:
    driver: bridge  # Public network
  internal:
    driver: bridge
    internal: true  # No external access

Identity Layer (Zitadel + Pomerium)

  • OIDC Authentication: Zitadel provides identity verification
  • PKCE Flow: Enhanced security for public clients
  • Access Proxy: Pomerium validates every request before routing
# From infra/docker-compose.yml:44-74
pomerium:
  image: pomerium/pomerium:latest
  environment:
    ZITADEL_CLIENT_ID: ${ZITADEL_CLIENT_ID}
    ZITADEL_CLIENT_SECRET: ${ZITADEL_CLIENT_SECRET}

Session Layer

All workspace sessions are monitored and auditable:
# From backend/server.py:78-91
class Session(BaseModel):
    id: str
    user_id: str
    workspace_id: str
    status: str  # active, disconnected, terminated
    tunnel_status: str = "encrypted"
    mfa_verified: bool = True

Multi-Factor Authentication

MFA Enforcement

NeoSC enforces MFA through security policies:
# From backend/server.py:768-774
{
    "id": "pol-mfa-required",
    "name": "MFA Required",
    "description": "Enforce multi-factor authentication for all users",
    "type": "access",
    "rules": ["Require MFA for login", "WebAuthn preferred", "TOTP as fallback"]
}

MFA Status Tracking

All users have MFA enabled by default:
# From backend/server.py:41-49
class User(BaseModel):
    id: str
    email: str
    name: str
    organization: str = "Default Organization"
    role: str = "user"
    mfa_enabled: bool = True  # Default enabled
WebAuthn/FIDO2 implementation is currently in development (P1 priority). MFA is enforced at the Zitadel SSO layer for SSO users. Local auth users should migrate to SSO for full MFA support.

Implementing MFA with Zitadel

1

Enable MFA in Zitadel

Configure MFA policies in Zitadel management console:
  • Navigate to Organization Settings → Login Policy
  • Enable “Multi-Factor Authentication”
  • Select allowed methods: WebAuthn, OTP, SMS
2

Enforce MFA for NeoSC project

In Zitadel project settings:
  • Select your NeoSC application
  • Enable “Force MFA” option
  • Set MFA grace period if needed
3

Verify MFA in sessions

NeoSC tracks MFA verification in session objects:
# backend/server.py:619-660
session = Session(
    user_id=user['id'],
    mfa_verified=user.get('mfa_enabled', True)
)

WebAuthn Registration (Planned)

Future implementation will support:
  • Hardware security keys (YubiKey, Titan, etc.)
  • Platform authenticators (Touch ID, Windows Hello)
  • Passwordless authentication

Security Policies

NeoSC implements three core security policies:

1. MFA Required Policy

# backend/server.py:768-774
{
    "id": "pol-mfa-required",
    "type": "access",
    "enabled": True,
    "rules": [
        "Require MFA for login",
        "WebAuthn preferred",
        "TOTP as fallback"
    ]
}
Enforcement: Integrated with Zitadel authentication flow.

2. Zero Trust Network Policy

# backend/server.py:776-782
{
    "id": "pol-network-zero-trust",
    "type": "network",
    "enabled": True,
    "rules": [
        "No direct connections",
        "WireGuard encryption",
        "Identity verification"
    ]
}
Enforcement: NetBird tunnels required for internal resource access.

3. Session Recording Policy

# backend/server.py:784-791
{
    "id": "pol-session-recording",
    "type": "session",
    "enabled": True,
    "rules": [
        "Record screen activity",
        "Log keystrokes for audit",
        "30-day retention"
    ]
}
Session recording playback is planned for P1 implementation. Recording infrastructure requires VDI backend integration (Kasm/Guacamole).

Managing Policies

Admins can toggle policies via API:
PATCH /api/policies/{policy_id}
Authorization: Bearer <admin_token>
Implementation:
# backend/server.py:805-819
@api_router.patch("/policies/{policy_id}")
async def toggle_policy(policy_id: str, user: dict = Depends(get_current_user)):
    policy = await db.policies.find_one({"id": policy_id})
    new_status = not policy.get('enabled', True)
    await db.policies.update_one({"id": policy_id}, {"$set": {"enabled": new_status}})
Disabling security policies reduces system security posture. All policy changes are logged to audit trail for compliance review.

Authentication Security

Password Security

Local authentication uses SHA-256 hashing:
# backend/server.py:126-127
def hash_password(password: str) -> str:
    return hashlib.sha256(password.encode()).hexdigest()
Security Recommendation: Upgrade to bcrypt or Argon2 for production deployments. SHA-256 is vulnerable to rainbow table attacks despite being cryptographically secure.
Recommended implementation:
import bcrypt

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()

def verify_password(password: str, hash: str) -> bool:
    return bcrypt.checkpw(password.encode(), hash.encode())

Token Management

Bearer tokens are generated using cryptographically secure random:
# backend/server.py:129-130
def generate_token() -> str:
    return secrets.token_urlsafe(32)  # 256 bits of entropy
Token storage: In-memory dictionary (development)
active_tokens = {}  # backend/server.py:133
Production Recommendation: Use Redis or JWT with refresh tokens for token persistence across server restarts and horizontal scaling.

SSO Security (Zitadel)

Zitadel integration uses PKCE for enhanced security:
# backend/server.py:326-436
@api_router.post("/auth/token-exchange")
async def token_exchange(request: TokenExchangeRequest):
    # Exchange authorization code for tokens
    token_response = await http_client.post(
        f"{authority}/oauth/v2/token",
        data={
            'grant_type': 'authorization_code',
            'client_id': client_id,
            'code': request.code,
            'redirect_uri': request.redirect_uri,
            'code_verifier': request.code_verifier,  # PKCE verification
        }
    )
PKCE Benefits:
  • Prevents authorization code interception
  • No client secret required for public clients
  • Secure for single-page applications

Network Security

Pomerium Access Proxy

All external traffic routes through Pomerium:
# infra/docker-compose.yml:44-74
pomerium:
  networks:
    - proxy    # External access
    - internal # Backend access
  ports:
    - "443:443"
    - "80:80"   # Redirect to HTTPS
Security features:
  • TLS termination
  • OIDC authentication before routing
  • Header injection for user context
  • No direct backend exposure

Internal Network Isolation

# infra/docker-compose.yml:80-102
frontend:
  networks:
    - internal  # No external ports
  # Accessed only via Pomerium at portal.kappa4.com

backend:
  networks:
    - internal  # No external ports
  # Accessed only via Pomerium at api.portal.kappa4.com

CORS Configuration

Backend restricts cross-origin requests:
# backend/server.py:846-852
app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_origins=os.environ.get('CORS_ORIGINS', '*').split(','),
    allow_methods=["*"],
    allow_headers=["*"],
)
Set CORS_ORIGINS to specific domains in production:
CORS_ORIGINS=https://portal.kappa4.com,https://gate.kappa4.com

Audit and Compliance

Comprehensive Audit Logging

All security-relevant events are logged:
# backend/server.py:94-103
class AuditLog(BaseModel):
    id: str
    user_id: str
    user_email: str
    action: str
    resource: str
    details: str
    ip_address: str = "192.168.1.1"
    timestamp: datetime
    success: bool = True

Logged Security Events

ActionResourceDetails
registerauthUser registration with organization
loginauthLocal authentication attempt
sso_loginauthSSO login with provider and role
logoutauthSession termination
toggle_policypolicy:{id}Policy enabled/disabled
launch_workspaceworkspace:{id}Workspace launch with security context
disconnect_sessionsession:{id}Session disconnection

Audit Log Access

GET /api/audit-logs
Authorization: Bearer <token>
Access control:
# backend/server.py:739-744
@api_router.get("/audit-logs")
async def get_audit_logs(user: dict = Depends(get_current_user)):
    # Admins see all, users see only their own
    query = {} if user.get('role') == 'admin' else {"user_id": user['id']}

Compliance Features

SOC 2 Type II

Audit logs provide evidence for access controls, monitoring, and incident response requirements.

GDPR Compliance

User consent tracking, data access logs, and retention policies support data protection requirements.

ISO 27001

Security policies, access controls, and audit trails align with information security management standards.

HIPAA

Session recording and encrypted tunnels support healthcare data protection requirements.

Security Checklist

1

Enable SSO

Configure Zitadel SSO for all users instead of local authentication:
  • Centralized credential management
  • MFA enforcement at IdP level
  • Automatic role provisioning
2

Enforce MFA

Verify MFA policy is enabled:
GET /api/policies/pol-mfa-required
# Ensure "enabled": true
3

Configure Pomerium

Set up TLS certificates and authentication:
  • Use valid TLS certificates (Let’s Encrypt or corporate CA)
  • Configure Zitadel as IdP in Pomerium
  • Set secure cookie secrets
4

Deploy NetBird

Roll out NetBird client to all users:
  • Install NetBird on workstations
  • Authenticate against management server
  • Verify tunnel connectivity
5

Review Audit Logs

Regularly monitor for suspicious activity:
GET /api/audit-logs?success=false
# Review failed authentication attempts
6

Rotate Secrets

Update credentials periodically:
  • Pomerium shared secret
  • Pomerium cookie secret
  • JWT signing keys
  • Database credentials

Environment Security

Production Environment Variables

Backend (backend/.env):
MONGO_URL=mongodb://mongo:27017/neosc
DB_NAME=neosc
JWT_SECRET=<strong-random-secret>
ZITADEL_AUTHORITY=https://manager.kappa4.com
ZITADEL_CLIENT_ID=<your-client-id>
ZITADEL_CLIENT_SECRET=<your-client-secret>
ZITADEL_PROJECT_ID=<your-project-id>
CORS_ORIGINS=https://portal.kappa4.com
TRUST_POMERIUM_HEADERS=true
Pomerium (.env):
ZITADEL_CLIENT_ID=<your-client-id>
ZITADEL_CLIENT_SECRET=<your-client-secret>
POMERIUM_SHARED_SECRET=<256-bit-base64>
POMERIUM_COOKIE_SECRET=<256-bit-base64>
Never commit secrets to version control. Use secret management solutions:
  • Docker secrets
  • Kubernetes secrets
  • HashiCorp Vault
  • AWS Secrets Manager

Secret Generation

Generate secure secrets:
# Pomerium shared secret (256 bits)
openssl rand -base64 32

# Pomerium cookie secret (256 bits)
openssl rand -base64 32

# JWT secret
openssl rand -hex 32

Incident Response

Detecting Security Events

Failed authentication attempts:
GET /api/audit-logs
# Filter for success: false, action: login
Unauthorized access attempts:
# Monitor 403 Forbidden responses in Pomerium logs
docker logs pomerium | grep "403"
Suspicious session activity:
GET /api/sessions
# Check for unusual IP addresses or session durations

Response Procedures

1

Identify the threat

Review audit logs to determine scope and impact of security event.
2

Contain the breach

Immediately revoke compromised credentials:
# Force logout
POST /api/auth/logout
Authorization: Bearer <compromised_token>
3

Disable affected accounts

For SSO users, disable in Zitadel. For local users, consider implementing account suspension endpoint.
4

Rotate secrets

Update all authentication secrets and redeploy services.
5

Document incident

Create incident report including:
  • Timeline of events
  • Affected users and resources
  • Response actions taken
  • Preventive measures implemented

Best Practices Summary

  • Use Zitadel SSO instead of local authentication
  • Enforce MFA for all users, especially admins
  • Rotate JWT secrets every 90 days
  • Implement account lockout after failed attempts (future)
  • Follow principle of least privilege
  • Assign admin role only when necessary
  • Review role assignments quarterly
  • Audit admin actions regularly
  • Require NetBird tunnels for all internal resources
  • Use Pomerium for external access only
  • Disable direct backend/frontend port exposure
  • Implement network segmentation
  • Enable all security policies
  • Review audit logs weekly
  • Set up alerts for failed authentications
  • Monitor session durations and IP addresses
  • Encrypt data at rest (MongoDB encryption)
  • Use TLS for all network traffic
  • Implement session recording for compliance
  • Define data retention policies

Build docs developers (and LLMs) love