# ============================================ # TAMGA — Environment Variables # Copy to .env and fill in your values # NEVER commit .env to version control. # ============================================ # --- Docker Compose profile --- # Which services `docker compose --env-file .env -f deploy/docker-compose.yml` # starts when no --profile flag is given. "full" is the whole stack; add # ",classifier" for the inline classifier. A --profile flag replaces this # value: `--profile minimal` starts the proxy alone, with no database. # See docs/operations.md, "Docker Compose profiles". COMPOSE_PROFILES=full # --- Required secrets for the full profile --- # Empty placeholders fail closed: fill them before starting the full stack. # Generate: openssl rand -hex 32 # The proxy-only profile (minimal) uses TAMGA_ADMIN_KEY alone, and only for # the management API. TAMGA_ADMIN_KEY= POSTGRES_PASSWORD= REDIS_PASSWORD= # One token per internal service, each its own `openssl rand -hex 32`. # Compose gives each to its service and to the proxy, which sends it with # every call. While TAMGA_REQUIRE_SERVICE_TOKENS is on (the Compose default) # the analyzer, the scanner service and the proxy do not start without # theirs, nor the classifier when its profile is used. # See docs/operations.md, "Internal service tokens". TAMGA_ANALYZER_TOKEN= TAMGA_SCANNER_SERVICE_TOKEN= TAMGA_CLASSIFIER_TOKEN= # TAMGA_REQUIRE_SERVICE_TOKENS=true # --- Go Proxy --- TAMGA_PROXY_PORT=8443 # Host interfaces and ports of the two published addresses. In the full # profile both belong to the TLS edge (Caddy), which serves HTTPS on them; # in the minimal profile the proxy's port is the proxy's own. Use 127.0.0.1 # when a reverse proxy on the same host is the only client that should # reach them. TAMGA_PROXY_BIND=0.0.0.0 TAMGA_DASHBOARD_BIND=0.0.0.0 TAMGA_DASHBOARD_PORT=3000 # --- TLS edge (full profile) --- # The addresses the edge serves. localhost and other internal names get a # certificate from the edge's local CA; a public DNS name gets one from # Let's Encrypt (add deploy/docker-compose.public.yml for port 80). Keep the # ports 8443 and 3000: they are the container's. http:// serves plain HTTP, # for example http://:8443 and http://:3000; then set NEXT_PUBLIC_API_URL # and TAMGA_CORS_ORIGINS to http:// too. See docs/operations.md, "TLS". # TAMGA_PROXY_SITE=https://localhost:8443 # TAMGA_CONSOLE_SITE=https://localhost:3000 # The proxy service reads ../.env too (relative to deploy/docker-compose.yml), # so settings not repeated in Compose still reach the process. Set this when # the Compose --env-file has another name. # TAMGA_PROXY_ENV_FILE=../.env # Compose supplies the policy path and the internal analyzer, database, Redis, # NATS and trace collector addresses. Uncomment an address only to use a # service outside this Compose project. # TAMGA_ANALYZER_ADDR=analyzer.example.invalid:50051 # TAMGA_ANALYZER_HTTP_URL=https://analyzer.example.invalid # TAMGA_DB_URL=postgresql://tamga:password@db.example.invalid:5432/tamga # REDIS_URL=redis://:password@cache.example.invalid:6379 # TAMGA_NATS_URL=nats://events.example.invalid:4222 # TAMGA_CLERK_SECRET_KEY= # Sessions and GitHub sign-in (optional; Compose passes these to the proxy). # Left out, there are no sessions and the admin key and API keys are the only # way in. TAMGA_JWT_SECRET signs the session tokens; generate it with # `openssl rand -hex 32` and keep it as secret as the admin key. GitHub # sign-in also needs an OAuth app: its client id and secret, and its redirect # URI, which ends in /api/v1/auth/github/callback. # TAMGA_JWT_SECRET= # TAMGA_GITHUB_CLIENT_ID= # TAMGA_GITHUB_CLIENT_SECRET= # TAMGA_GITHUB_OAUTH_CALLBACK_URL= # The role of a signed-in account nobody gave one. Empty refuses it; `viewer` # is the only other value. # TAMGA_SSO_DEFAULT_ROLE= # The key the request log hashes finding matches under (HMAC-SHA-256) when # the policy has data.hash_findings on. Standard base64 of 32 random bytes # or more: `openssl rand -base64 32`. Left out, a key is derived from # TAMGA_VAULT_KEY; with neither, matches are not stored at all. Keep it # across restarts and the same on every replica: under another key the # stored hashes are no longer found. # TAMGA_FINDING_HASH_KEY= # Comma-separated origins allowed to call the management API (exact match): # the console's address as the browser sees it. TAMGA_CORS_ORIGINS=https://localhost:3000 # Demo / security hardening TAMGA_MAX_BODY_BYTES=1048576 TAMGA_MOCK_UPSTREAM=false TAMGA_OTEL_SAMPLE_RATE=0.05 TAMGA_REQUIRE_KEY=false TAMGA_KEY_IN_PATH=false TAMGA_RETENTION_ENABLED=true TAMGA_POLICY_MOUNT=ro # Delegate stateless scanning to the full profile's scanner service. # TAMGA_SCANNER_SERVICE_ADDR=scanner-service:50052 # Enable only together with the classifier profile and policy setting. # TAMGA_CLASSIFIER_ADDR=classifier:50052 # Jaeger and NATS monitoring are loopback-only by default. Setting this to # 0.0.0.0 makes both unauthenticated interfaces reachable from the network. TAMGA_OBSERVABILITY_BIND=127.0.0.1 # --- Python Analyzer --- TAMGA_ANALYZER_PORT=8444 TAMGA_GRPC_PORT=50051 TAMGA_ANALYZER_WORKERS=2 # Leave provider keys empty unless the corresponding feature needs one. # The analyzer's LLM judge is off unless both of these are set: # TAMGA_LLM_JUDGE=anthropic and a real ANTHROPIC_API_KEY. A key alone does # not turn it on, and a placeholder is refused. When on, the analyzer sends # up to the first 2000 characters of a request to Anthropic, for requests # the proxy forwarded and hands over (TAMGA_ANALYZER_SEND_CONTENT below); # never for one the proxy blocked. See docs/operations.md, "Analyzer". TAMGA_LLM_JUDGE= ANTHROPIC_API_KEY= # Proxy: copy the text of forwarded requests to the analyzer for analysis # after the decision. Off by default; without it the analyzer serves the # PDF reports and reads no request text. TAMGA_ANALYZER_SEND_CONTENT=false OPENAI_API_KEY= # --- Next.js Dashboard --- # The dashboard holds no admin key: each person enters one under Settings and # it stays in their browser. Do not set NEXT_PUBLIC_ADMIN_KEY here: a # NEXT_PUBLIC_ value is compiled into the JavaScript every visitor downloads, # and a production build of the dashboard stops when it is set. It is a # convenience for `next dev` only, in dashboard/.env.local. # The address the browser reaches the proxy at. It is compiled into the # dashboard image: after changing it, run `docker compose build dashboard`. # The proxy's TAMGA_CORS_ORIGINS must list the dashboard's own address. NEXT_PUBLIC_API_URL=https://localhost:8443 # Public links used by the console. These are compiled into its image too. NEXT_PUBLIC_SITE_URL=https://tamgaproxy.com NEXT_PUBLIC_MARKETING_URL=https://tamgaproxy.com # --- Standalone scanner service --- SCANNER_SERVICE_PORT=50052 SCANNER_PIPELINE_MODE=adaptive SCANNER_WORKER_POOL_SIZE=4 SCANNER_WORKER_QUEUE_SIZE=0 # --- Inline classifier service (classifier profile) --- TAMGA_CLASSIFIER_PORT=50052 TAMGA_CLASSIFIER_MODEL_NAME=prompt-injection-guard-small TAMGA_CLASSIFIER_THREADS=0 TAMGA_CLASSIFIER_WINDOW=512 TAMGA_CLASSIFIER_OVERLAP=64 TAMGA_CLASSIFIER_MAX_WINDOWS=16 # TAMGA_CLASSIFIER_MODEL_PATH=../models/prompt-injection-guard-small # Shadow mode (off while the directory is empty): a candidate injection model # scored next to the one above, recorded and never acted on. # TAMGA_CLASSIFIER_SHADOW_MODEL_PATH=../models/shadow # TAMGA_CLASSIFIER_SHADOW_MODEL_NAME= # TAMGA_CLASSIFIER_SHADOW_THREADS=0 # TAMGA_CLASSIFIER_SHADOW_WAIT_MS=20 # --- Alerts --- SLACK_WEBHOOK_URL= # --- Resource limits (Compose) --- # CPU and memory limits per service; see docs/operations.md, "Resource # limits", for the defaults and how they were chosen. A CPU limit above the # host's core count stops that container from starting. # TAMGA_PROXY_CPUS=2 # TAMGA_PROXY_MEMORY=1g # TAMGA_CLASSIFIER_CPUS=2 # TAMGA_CLASSIFIER_MEMORY=3g # --- TLS on the proxy itself (minimal profile, Helm) --- # The full profile's edge ends TLS; leave these empty there. # TAMGA_TLS_CERT=/path/to/cert.pem # TAMGA_TLS_KEY=/path/to/key.pem # TAMGA_MTLS_CLIENT_CA_FILE=/path/to/ca.pem