Skip to content

Configuration

WhiteMuush edited this page Sep 1, 2026 · 3 revisions

Configuration

DataShield is configured entirely through environment variables, loaded from .env.local in development. Copy .env.example to start.

Required

Variable Purpose
DATABASE_URL PostgreSQL connection string. Matches compose.yml defaults so npm run db:init works out of the box.
BETTER_AUTH_SECRET Better Auth session and token signing secret. Generate with openssl rand -base64 32.
DIRECTORY_ENCRYPTION_KEY 32 characters minimum. Encrypts directory connection secrets, API keys, and webhook URLs at rest (AES-256-GCM). The app refuses to handle directory configs without it.

Optional

Variable Purpose
BETTER_AUTH_URL Base URL of the app. Override only if you are not on http://localhost:3000.
HIBP_API_KEY Enables Have I Been Pwned breach lookups. (Per-company keys can also be stored in the app via Data API.)
RESEND_API_KEY Enables email alerts to company admins on new breach exposures.
EMAIL_FROM Sender for alert emails, e.g. DataShield <alerts@yourdomain.com>.
SEED_ADMIN_EMAIL Override the seeded admin email (default admin@datashield.local).
SEED_ADMIN_PASSWORD Override the seeded admin password (default ChangeMe123!).
CRON_SECRET Bearer token guarding POST /api/cron. Required to drive the scheduler (auto scan/sync, scheduled reports, SIEM push). Without it the endpoint returns 503.
DIRECTORY_ENCRYPTION_KEY_PREVIOUS Set only during key rotation: the former DIRECTORY_ENCRYPTION_KEY. Decryption falls back to it so existing rows stay readable until they are re-encrypted. Remove it once rotation is done.

Email is all-or-nothing. Both RESEND_API_KEY and EMAIL_FROM must be set, otherwise notifications are skipped silently.

Scheduler

Time-driven work (auto scan and sync, scheduled report delivery, SIEM push) is not a long-running daemon: an external scheduler POSTs /api/cron on a fixed interval, authenticated with CRON_SECRET. Each tick runs only the work that is due. See SIEM Integration and Reports.

curl -X POST -H "authorization: Bearer $CRON_SECRET" https://host/api/cron

How keys are stored

Breach-provider API keys, directory-connection configs, and webhook URLs are never stored in plaintext. They are encrypted with AES-256-GCM using a key derived (via SHA-256) from DIRECTORY_ENCRYPTION_KEY, and only the host portion (urlHint / keyHint) is kept readable for display. See Security.

Rotating the encryption key

Changing DIRECTORY_ENCRYPTION_KEY without a rotation path makes every stored secret undecryptable. The supported sequence is:

  1. Move the current value to DIRECTORY_ENCRYPTION_KEY_PREVIOUS.
  2. Set DIRECTORY_ENCRYPTION_KEY to the new value.
  3. Restart, then run npm run reencrypt:directory to rewrite existing rows under the new key.
  4. Remove DIRECTORY_ENCRYPTION_KEY_PREVIOUS.

The key length check is enforced at runtime: anything shorter than 32 characters throws on first encrypt or decrypt, so the app fails closed rather than degrading to plaintext.

Clone this wiki locally