Skip to main content

Documentation Index

Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt

Use this file to discover all available pages before exploring further.

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

Supply Chain

LangWatch container images and CLI packages are published with verifiable supply-chain attestations so operators can confirm an artifact was built by LangWatch CI from a specific source commit.

Container images (Docker Hub)

Every release of langwatch/langwatch, langwatch/langwatch_nlp, langwatch/langevals, and langwatch/ai-gateway is signed with Sigstore cosign using keyless OIDC. Both the multi-arch index manifest and each per-platform manifest (linux/amd64, linux/arm64) are signed by digest. A CycloneDX SBOM is generated per platform and attached as a cosign attestation against the matching platform manifest digest, so the SBOM you verify always corresponds to the architecture you actually pulled. Verify a signature with cosign:
cosign verify langwatch/langwatch:<tag> \
  --certificate-identity-regexp '^https://github\.com/langwatch/langwatch/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
Inspect the attached SBOM for the platform you pulled (cosign resolves the right per-platform manifest digest automatically when you pass a tag):
cosign download attestation \
  --predicate-type https://cyclonedx.org/bom \
  langwatch/langwatch:<tag> \
  | jq -r '.payload | @base64d | fromjson | .predicate' \
  > langwatch.cdx.json
The per-platform *.cdx.json files (e.g. langwatch-linux-amd64.cdx.json, langwatch-linux-arm64.cdx.json) are also attached to each langwatch@vX.Y.Z GitHub release.

npm CLI

The langwatch npm package is published with npm provenance attestations via GitHub Actions OIDC, also backed by Sigstore. The provenance link is visible on the package page and can be verified with npm audit signatures.

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)
  • Image signatures verified at pull time (admission controller or cosign verify in CI)