Skip to main content
This page covers the security features and best practices for self-hosted LangWatch deployments.

Authentication & Authorization

NextAuth.js handles user authentication with support for:
  • Email/password (default)
  • SSO providers: Azure AD, Okta, Auth0, AWS Cognito, Google, GitHub, GitLab
See SSO Configuration for setup guides. Role-Based Access Control (RBAC) controls what users can do within a project:
  • Organization-level roles (owner, admin, member)
  • Project-level permissions
SCIM provisioning (Enterprise) enables automated user lifecycle management from your identity provider. API tokens are signed with JWT (API_TOKEN_JWT_SECRET) for SDK authentication.

Encryption

At Rest

Data StoreEncryption Method
PostgreSQLProvider-level encryption (RDS: AES-256, Cloud SQL: AES-256)
ClickHouseEncrypted volumes (EBS encryption, PD encryption)
S3Server-side encryption (SSE-S3 or SSE-KMS)
Stored credentialsApplication-level encryption via CREDENTIALS_SECRET
The CREDENTIALS_SECRET environment variable is used to encrypt API keys and credentials stored in PostgreSQL (e.g., LLM provider keys configured in the UI). This is application-level encryption on top of database-level encryption.

In Transit

PathEncryption
Client to AppTLS at Ingress / Load Balancer
App to PostgreSQLTLS (configure via connection string: ?sslmode=require)
App to ClickHouseHTTPS (configure ClickHouse with TLS certificates)
App to RedisTLS (configure via connection string: rediss://...)
Inter-service (App, Workers, NLP, LangEvals)Plain HTTP within cluster (use a service mesh for mTLS)
For inter-service encryption, deploy a service mesh like Istio or Linkerd. This adds mTLS between all pods without application changes.

Secrets Management

Development (Auto-Generated)

For development, enable autogen.enabled: true in the Helm chart. This generates random secrets automatically. Not suitable for production — secrets change on reinstall.

Production (Kubernetes Secrets)

Create secrets manually and reference them in the Helm chart:
kubectl create secret generic langwatch-secrets \
  --namespace langwatch \
  --from-literal=credentialsEncryptionKey=$(openssl rand -hex 32) \
  --from-literal=nextAuthSecret=$(openssl rand -hex 32) \
  --from-literal=cronApiKey=$(openssl rand -hex 32)
Reference in values.yaml:
secrets:
  existingSecret: langwatch-secrets

Production (External Secret Managers)

For tighter security, use an external secrets operator to sync secrets from your cloud provider: The Helm chart’s secretKeyRef pattern works with any Kubernetes Secret, regardless of how it was created.

Network Security

  • Only the LangWatch App should be exposed externally via Ingress or Load Balancer
  • All other components (Workers, NLP, LangEvals, PostgreSQL, ClickHouse, Redis) should be on internal networks only (ClusterIP services)
  • Place databases in private subnets with no internet access
  • Use VPC endpoints / PrivateLink for S3 access

Kubernetes Network Policies

Restrict traffic between pods:
# Example: only allow app and workers to reach ClickHouse
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: clickhouse-access
  namespace: langwatch
spec:
  podSelector:
    matchLabels:
      app: clickhouse
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app.kubernetes.io/component: app
        - podSelector:
            matchLabels:
              app.kubernetes.io/component: workers
      ports:
        - port: 8123

Firewall Rules

SourceDestinationPortProtocol
Internet / VPNApp (Ingress)443HTTPS
AppPostgreSQL5432TCP
App, WorkersClickHouse8123HTTP
App, WorkersRedis6379TCP
WorkersNLP5561HTTP
WorkersLangEvals5562HTTP
NLP, LangEvalsExternal LLMs443HTTPS
CronJobsApp5560HTTP

Pod Security

The Helm chart applies secure defaults to all pods:
# Pod-level (applied via global.podSecurityContext)
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000

# Container-level (applied via global.containerSecurityContext)
allowPrivilegeEscalation: false
capabilities:
  drop:
    - ALL
readOnlyRootFilesystem: true
These ensure:
  • No containers run as root
  • No privilege escalation is possible
  • Containers cannot modify their own filesystem
  • All Linux capabilities are dropped

PII Redaction

LangWatch includes a built-in PII redaction pipeline step that automatically detects and masks personally identifiable information in traces before storage.
  • Enabled by default in the Helm chart
  • Disable with app.features.disablePiiRedaction: true (not recommended)
  • Runs as part of the event sourcing pipeline in workers

Multitenancy

LangWatch enforces tenant isolation at the application level:
  • Every ClickHouse query includes WHERE TenantId = ... as the first predicate
  • PostgreSQL queries include projectId in WHERE clauses
  • API tokens are scoped to a specific project
  • Cross-tenant data access is prevented at the query layer

Production Hardening Checklist

  • autogen.enabled: false — use manually created secrets
  • All secrets stored in a secrets manager (not inline in values.yaml)
  • TLS enabled on Ingress (HTTPS only)
  • Database connections use TLS (?sslmode=require)
  • PostgreSQL, ClickHouse, Redis in private subnets (no public access)
  • Network policies restrict pod-to-pod traffic
  • S3 buckets have public access blocked
  • ClickHouse backups enabled and tested
  • Monitoring and alerting configured
  • Secret rotation procedure documented
  • Pod security contexts verified (non-root, read-only filesystem)
  • Ingress rate limiting configured
  • Audit logs enabled (Enterprise)