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.
| Piece | Where It Lives | Safe to Commit? |
|---|---|---|
.env.vault | Git repo | Yes -- encrypted ciphertext |
DOTENV_KEY | GitLab CI variables / Heroku config vars | No -- 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.
- The
build-vaultjob runs in thedetectstage using aDOTENV_MEservice credential (stored in GitLab CI variables, Protected + Masked) - It calls
npx dotenv-vault buildwhich fetches all environments from dotenv.org and produces a fresh.env.vault - The artifact is passed to all 6 deploy jobs (dev, qa, uat, staging, prod, prod-hotfix)
- Each deploy job uses its own
DOTENV_KEYto 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
| File | Purpose | In Git? | Contains Secrets? |
|---|---|---|---|
.env | Local development variables | No (gitignored) | Yes (plaintext) |
.env.vault | Encrypted secrets for all deployed environments | Yes | No (ciphertext only) |
.env.me | Your personal dotenv.org credential | No (gitignored) | Yes (auth token) |