Why this matters for Analytics Engineers
Analytics Engineers handle credentials for warehouses, BI tools, ELT/ETL jobs, and automation. A single leaked secret can expose customer data, break pipelines, or cause downtime. This lesson shows how to keep secrets out of Git, set up safe local workflows, and rotate credentials quickly when something leaks.
- dbt profiles, warehouse passwords, and service tokens must never be committed.
- CI/CD often needs secrets; you pass them securely, not via repository files.
- Rotation keeps access safe after incidents or team changes.
Concept explained simply
A secret is any value that grants access: API keys, passwords, tokens, private keys, connection strings. Git is permanent and shareable; if a secret enters Git history, assume it's leaked.
Mental model
Think of secrets like physical keys. Keys live on your keyring (environment/secret manager), not glued to your project notebook (the repo). If you lose a key, you change the lock (rotate) and issue a new key.
- Keep secrets out of Git. Store placeholders/templates in Git.
- Load real values at runtime (env vars/secret manager).
- Rotate promptly after any exposure or scheduled interval.
Minimal safe setup (local)
- Create a local .env with real values, and a committed .env.example with placeholders:
# .env (do NOT commit)
DB_USER=analytics_ro
DB_PASSWORD=supersecret
DB_HOST=warehouse.local
# .env.example (commit this)
DB_USER=YOUR_DB_USER
DB_PASSWORD=YOUR_DB_PASSWORD
DB_HOST=YOUR_DB_HOST
- Ignore local secret files:
# .gitignore entries
.env
.env.*
!.env.example
- Commit safe files only:
git add .gitignore .env.example
git rm --cached .env 2>/dev/null || true
git commit -m "chore(security): ignore .env and add template"
- Load secrets at runtime via your tool or shell (example shown as concept):
# Example (shell): export vars from .env for local run
set -a; [ -f ./.env ] && . ./.env; set +a
# Then run your tool (example)
dbt debug # it will read env vars via your profiles config
Result: collaborators can run the project using their own local .env, with no secrets stored in Git.
Worked examples
Example 1 — You accidentally committed .env
- Immediately rotate the exposed secret (create a new token/password, plan to revoke old one).
- Remove the file from the index and commit the fix:
git rm --cached .env
printf ".env\n.env.*\n!.env.example\n" >> .gitignore
git commit -m "chore(security): stop tracking .env and update .gitignore"
- Force everyone to use their own local .env. Keep the rotated secret active only after your code/config uses it, then revoke old secret.
About history
Removing a file from the index does not purge it from past commits. For recent commits, you might amend or reset and recommit without the file. For older commits, consider a full history rewrite using a dedicated tool, then rotate secrets regardless. Rotation is non-negotiable after any leak.
Example 2 — Rotating a dbt profile password
- Generate new DB password in your warehouse (new_secret).
- Add new_secret to your local environment (.env) and CI secret store.
- Deploy config change (no secrets in code). Verify with a connection test.
- Revoke the old password. Monitor logs for failures.
Example 3 — Removing a secret from the last commit
- Revoke/rotate the secret first.
- Undo the last commit, keep changes staged:
git reset --soft HEAD~1
- Unstage/remove the secret file, add safe files only, recommit:
git rm --cached .env
git add .gitignore .env.example other_safe_files
git commit -m "fix(security): remove secret from commit and add ignore rules"
Push the corrected commit. Coordinate with collaborators if they already pulled the bad commit.
Rotation playbook (use this when a secret might be exposed)
- Plan: Identify scope (where used: local, CI, prod).
- Create new: Generate a new credential with same permissions.
- Update consumers: Put new secret in local envs and CI secret storage.
- Cutover: Deploy and verify using the new secret.
- Revoke old: Disable old credential once traffic uses the new one.
- Confirm: Run tests, check logs/alerts.
- Document: Note when/why rotated, where stored.
Tools and choices (conceptual)
- Environment variables: simplest local approach; pair with .env ignored by Git.
- CI/CD secret store: define secrets in pipeline settings; referenced as environment variables.
- OS keychain/credential store: keep values off disk where possible.
- Encrypted files in Git: possible but risky for basics; key management becomes complex. Prefer secret managers unless you fully understand the implications.
- Scanning: use pre-commit or CI scanners to catch accidental secrets before merge.
Team conventions to adopt
- Never commit real secrets. Commit .env.example with placeholders.
- Use clear commit messages for security work: chore(security) or fix(security).
- Review PRs for secret exposure (humans + scanners).
- Rotate on schedule (e.g., quarterly) and after any suspected leak.
- Document where secrets live and who to contact for rotation.
Exercises
Complete Exercise 1 below. If logged in, your progress on the quick test is saved; exercises are available to everyone.
Exercise 1 — Set up safe .env workflow and simulate a rotation
- Initialize a sample repo. Create .env (realistic values) and .env.example (placeholders).
- Add ignore rules so .env will never be committed.
- Commit only safe files and verify git status shows .env as untracked.
- Simulate a rotation: change DB_PASSWORD in .env to a new value; ensure no Git changes appear except where appropriate (none to commit).
What to submit
- Screenshot or copy of your .gitignore and .env.example content.
- Terminal snippet showing .env is untracked and a commit message adding .env.example.
Self-check checklist
- .env is ignored and never staged.
- .env.example contains placeholders only.
- git status shows no changes when rotating a secret locally.
- Commit message includes a clear security tag, e.g., chore(security).
Common mistakes and how to self-check
- Mistake: Relying on .gitignore after a secret was already committed. Self-check: run git log -p on the offending path; if present in history, rotate and consider rewriting history.
- Mistake: Committing real values in .env.example. Self-check: search for DB_PASSWORD= or API_KEY= patterns; examples must be placeholders.
- Mistake: Rotating without updating all consumers. Self-check: list environments (local, CI, prod) and confirm each has the new secret.
- Mistake: Leaving old secrets active. Self-check: ensure old token is revoked/disabled and cannot be used.
Mini challenge
Your teammate pushed a commit containing a warehouse password 15 minutes ago. Draft a 5-step action note you would post in the team channel to coordinate rotation and cleanup. Include: immediate rotation, code/config update, verification, revocation, and a follow-up checklist.
One possible outline
- Rotate: Creating new password now; will add to CI and share via secure channel.
- Update: Switching env vars in CI and my local .env; asking others to pull latest once done.
- Verify: Running connection tests and a small job run.
- Revoke: Disabling old password once tests pass.
- Follow-up: Add .gitignore rule, commit .env.example, consider history cleanup, and document incident.
Who this is for
- Analytics Engineers and BI Developers who manage data pipelines and credentials.
- Anyone pushing to Git who may handle API keys or database access.
Prerequisites
- Basic Git fluency: add, commit, status, log.
- Ability to run shell commands locally.
- Familiarity with environment variables.
Learning path
- Before: Git basics, branching, and PRs.
- Now: Storing and rotating secrets safely (this lesson).
- Next: CI/CD with secret stores; pre-commit secret scanning; incident response drills.
Practical projects
- Create a small dbt or SQL project with .env.example, run locally using env vars only.
- Set up a pre-commit hook that blocks accidental secret patterns.
- Write a team rotation checklist and test it with a dummy token.
Next steps
- Adopt .env.example and .gitignore in all repos.
- Introduce a simple secret scanning step in your workflow.
- Schedule periodic rotations and document ownership.
FAQ
Is it ever okay to keep encrypted secrets in Git?
Only if your team fully understands key management, access control, and rotation implications. For basics, prefer environment variables and a secret manager integrated with CI/CD.
Does .gitignore remove secrets from history?
No. It only prevents future tracking. If a secret was committed, rotate it and consider history cleanup.
How often should we rotate?
On a schedule (e.g., quarterly) and immediately after any suspected exposure or team member offboarding.
About progress
The quick test and exercises are available to everyone. If you are logged in, your test progress is saved so you can return and continue.