Skip to main content

Environments and Sensitive Runtime Config

Last updated: 2026-03-21

This document defines the operational pattern for sensitive configuration in this repo: version templates, generate runtime JSON outside Git, and resolve secrets from .env.secrets.

Generated configs

These files must no longer be versioned:

  • platform/portal/ui/src/config/subsystems.json
  • infrastructure/chat-server/config/mcp_services.json
  • infrastructure/chat-server/config/llm_providers.json
  • infrastructure/chat-server/config/llm_embeddings.json

The versioned sources are their corresponding .template files.

Canonical sources

  • Shared secrets: /.env.secrets
  • Non-sensitive config and aliases: /.env
  • Per-stack overrides: <stack>/.env

Root keys used by this flow:

  • GLOBAL_CHATWOOT_PLATFORM_TOKEN
  • GLOBAL_THINGSBOARD_SYSTEM_USER_SECRET
  • GLOBAL_GOOGLE_GENAI_API_KEY
  • GLOBAL_NVIDIA_API_KEY
  • GLOBAL_OPENAI_API_KEY
  • THINGSBOARD_API_BASE_URL
  • THINGSBOARD_ADMIN_USER
  • THINGSBOARD_SYSTEM_USER_DOMAIN
  • CHATWOOT_API_BASE_URL

Operational commands

Generate .env, missing secrets, and runtime configs:

./infra.sh env generate

Regenerate only runtime JSON:

bash deployment/scripts/config-generators/generate-runtime-configs.sh

Scan for secrets in versioned files:

deployment/scripts/scan-secrets.sh

If you use pre-commit, the local hook is defined in .pre-commit-config.yaml.

New behavior

Chatwoot

  • platform/chatwoot/run.custom.sh platform-app no longer edits subsystems.json.
  • The Platform App token is stored in GLOBAL_CHATWOOT_PLATFORM_TOKEN.
  • Runtime config is regenerated afterwards.

ThingsBoard

  • The portal and chat-server no longer depend on a fixed password for technical users.
  • Technical username pattern: system_<entityId>@<THINGSBOARD_SYSTEM_USER_DOMAIN>.
  • Technical password is derived via HMAC-SHA256(GLOBAL_THINGSBOARD_SYSTEM_USER_SECRET, "<scope>:<entityId>").

chat-server / LLMs

  • Versioned providers use api_key_env.
  • Inline api_key is only allowed for safe values like lm-studio, no-key, or placeholders.
  • Fallback to FakeEmbeddings is only allowed with DEV_MODE=true.

n8n

  • The image is pinned via N8N_VERSION.
  • WEBHOOK_URL is now required.
  • Legacy ThingsBoard exports were sanitized and must be treated as reference material, not an authoritative secrets source.

Applied stack hardening

  • Kafka waits for a real ZooKeeper healthcheck.
  • ThingsBoard targets kafka:29092 and its wrapper won't start if Kafka is not healthy.
  • data-aggregator validates real TCP connectivity to Kafka.
  • Airflow stops bootstrapping airflow/airflow and loads apache-airflow-providers-influxdb.
  • Zitadel stops running as root and no longer mounts the whole repo.
  • Telegraf syncs its MQTT credentials from the Mosquitto stack.

Remediation still required outside the repo

These changes harden the future, but they do not rotate previously exposed secrets. You still need to rotate:

  • the current Chatwoot Platform App token,
  • ThingsBoard admin/technical credentials that were used with the prior fixed password,
  • any real Google/NVIDIA/OpenAI keys if they were ever committed.