Skip to main content

Secrets Vault

Fastlane uses dotenv-vault for encrypted secret management. All environment variables for every deployed environment live in a single encrypted file (.env.vault) that is safe to commit to Git. The file is useless without its decryption key, which is stored separately in GitLab CI/CD variables.

How It Works

The system is built on a split-knowledge model -- two pieces that are useless alone but combine to produce secrets at deploy time.

PieceWhere It LivesSafe to Commit?
.env.vaultGit repoYes -- encrypted ciphertext
DOTENV_KEYGitLab CI variables / Heroku config varsNo -- decryption key

An attacker who compromises the Git repo sees only ciphertext. An attacker who compromises GitLab CI variables has a key with nothing to decrypt. Both pieces are required.

Each environment (development, test, uat, preprod, production) has its own encryption key. Compromising one environment's DOTENV_KEY does not expose any other environment.

CI Auto-Build

The .env.vault file is rebuilt automatically in CI before every deploy. No one needs to manually run build or commit the vault.

  1. The build-vault job runs in the detect stage using a DOTENV_ME service credential (stored in GitLab CI variables, Protected + Masked)
  2. It calls npx dotenv-vault build which fetches all environments from dotenv.org and produces a fresh .env.vault
  3. The artifact is passed to all 6 deploy jobs (dev, qa, uat, staging, prod, prod-hotfix)
  4. Each deploy job uses its own DOTENV_KEY to decrypt only its environment's secrets

The .env.vault committed in Git serves as a fallback if dotenv.org is unreachable during CI.

Frontend vs API Gateway Decryption

The two app types decrypt secrets at different stages of the pipeline.

Frontend (Portal, Admin)

DOTENV_KEY is passed as a Docker build argument. A Node.js script decrypts the vault and writes all VITE_* variables to a .env file, which Vite reads during the build. The resulting static files have environment-specific values baked in -- the key is never present at runtime.

API Gateway

The Docker image ships with .env.vault inside it. When the container starts, node -r dotenv/config main.js reads DOTENV_KEY from the Heroku environment and decrypts the vault on the fly. Secrets are never written to disk -- they exist only in the Node.js process memory.

Why It's Secure

Split-knowledge encryption -- .env.vault (ciphertext) and DOTENV_KEY (decryption key) are stored in completely separate systems. Compromising one reveals nothing.

Per-environment isolation -- Each environment has its own unique DOTENV_KEY. Access to the dev key cannot decrypt production secrets.

No plaintext in Git -- .env is gitignored. .env.vault contains only AES-256-GCM encrypted blobs. .env.me (personal credential) is gitignored.

Restricted access control -- Developers have pull-only access on dotenv.org. Push access (which overwrites an entire environment) is restricted to admins. Deployed environments can only be edited through the dotenv.org web UI, which modifies individual fields.

Protected CI credentials -- DOTENV_KEY values and DOTENV_ME are configured as Protected + Masked variables in GitLab, meaning they are only available on protected branches and hidden from job logs.

No secrets in Docker layers -- Frontend apps discard the key after the build stage (multi-stage Docker build). The API gateway receives the key as a runtime environment variable, never written to the image filesystem.

Automated vault rebuild -- The build-vault CI job fetches secrets fresh from dotenv.org before every deploy, eliminating stale-vault drift between what's on dotenv.org and what's deployed.

Developer Quick Start

Three commands are all you need:

npx dotenv-vault@latest login
npx dotenv-vault@latest pull

login authenticates you with dotenv.org (one-time). pull downloads the local environment to your .env file.

To stay up to date after secret changes:

npx dotenv-vault@latest pull

Need a variable added, changed, or removed? Message an admin/lead via Slack or Jira. See Updating Environment Variables for the full workflow.

Key Files

FilePurposeIn Git?Contains Secrets?
.envLocal development variablesNo (gitignored)Yes (plaintext)
.env.vaultEncrypted secrets for all deployed environmentsYesNo (ciphertext only)
.env.meYour personal dotenv.org credentialNo (gitignored)Yes (auth token)