~ /yaayes.dev
Home Blog Contact
← cd ..

Stop Hardcoding Your Passwords, You Animal!

· by Yassine Sedrani · 7 min read

We’ve all been there. You’re moving fast, the deadline is tomorrow, and you just need this thing to work. So you do the thing. The unspeakable thing.

db_password: "mySuperSecretPassword123"

And then you commit it. And push it. To a public repo.

Congratulations — your database credentials are now indexed by GitHub search and every bot on the internet is attempting to connect to your server as we speak.

Let’s fix that. For good.


The Problem With “I’ll Handle It Later”

Secrets management is one of those things everyone knows they should do properly, but nobody does until something goes wrong. And when something goes wrong with secrets, it’s not a “oops, fix it and move on” situation. It’s a “rotate every credential, audit every access log, notify your users” situation.

The good news? Doing it right is actually not that complicated. The approach just depends on your situation.


Scenario 1: You’re Flying Solo

You’re a solo dev. No team. Just you, your laptop, and an unhealthy amount of coffee. You don’t need an enterprise-grade secrets vault — but you do need something.

The Ansible Vault Approach

If you’re using Ansible (and you should be — more on that another time), Ansible Vault lets you encrypt individual values right inside your YAML files.

ansible-vault encrypt_string 'mySuperSecretPassword123' --name 'db_password'

This spits out something like:

db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  66386439653236336462626566653337396131333566316364373666653437396162393731343237
  3436643062343566626635663739653934663930386566310a316330623337313930626134326334
  ...

That blob is safe to commit. It’s AES-256 encrypted. Nobody’s reading that without your vault password.

When you run your playbook, Ansible asks for the vault password (or you point it to a password file):

ansible-playbook playbook.yml --ask-vault-pass
# or
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass

Where Do You Store the Vault Password?

Not in the repo. Never in the repo.

For solo work, your options are:

  • A file at ~/.vault_pass on your machine (never committed)
  • Your system keychain (macOS Keychain, GNOME Keyring)
  • A password manager like 1Password or Bitwarden

Add the password file to .gitignore:

.vault_pass
ansible/host_vars/

SSH Keys: Keep Them On Your Machine

Your personal SSH key (~/.ssh/id_rsa or ~/.ssh/id_ed25519) never leaves your machine. Full stop. You don’t commit it. You don’t send it over Slack. You don’t put it in a .env file.

Think of it like your house key. You wouldn’t photocopy it and tape it to the front door.


Scenario 2: You’re on a Small Team (2–10 People)

Now things get interesting. You’ve got a team. People are onboarding. Someone’s going on vacation. Another person just left. Suddenly “just keep it on your machine” doesn’t scale anymore.

Separate Concerns: Three Types of Keys

Before we go further, let’s get clear on the three types of SSH keys you’re dealing with:

Key TypeWho Has ItWhere It Lives
Personal keyIndividual developerTheir laptop only
Deploy keyThe serverServer’s ~/.ssh/, public key on GitHub
CI/CD keyGitHub Actions / your CIStored as a secret in the CI platform

These are three completely different things. Don’t conflate them.

Deploy Keys: One Key Per Repo

A deploy key is an SSH keypair where:

  • The private key lives on your server
  • The public key is registered on your GitHub repo as a “deploy key”

Generate one on your server:

ssh-keygen -t ed25519 -f ~/.ssh/my_project_deploy -N "" -C "deploy@my-project"

Add the public key to GitHub at Settings → Deploy keys. Give it read-only access. Done.

Now your server can pull from GitHub without your personal credentials being involved at all. If the server gets compromised, you revoke that one deploy key. Your personal access is untouched.

# ~/.ssh/config on the server
Host github-myproject
  HostName github.com
  User git
  IdentityFile ~/.ssh/my_project_deploy

Sharing the Vault Password With Your Team

For a small team, you have a few options:

Option A: Shared password manager Use 1Password Teams, Bitwarden Organizations, or similar. Create a shared vault. Put the Ansible vault password there. Everyone on the team gets access. When someone leaves, you change the password, re-encrypt, and update the shared vault.

Option B: ansible-vault with key per environment Use different vault passwords for staging vs production. Staging password is more widely shared. Production password is restricted to whoever actually deploys to prod.

ansible-vault encrypt_string 'stagingPassword' --name 'db_password' --vault-id staging@~/.vault_pass_staging
ansible-vault encrypt_string 'prodPassword' --name 'db_password' --vault-id prod@~/.vault_pass_prod

Option C: A dedicated secrets manager If you’re already on AWS, Azure, or GCP, use their native secrets managers (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager). More setup, but much better audit trails and access control.

The “Someone Just Left” Protocol

When a team member leaves:

  1. Rotate the vault password — re-encrypt all secrets with a new password
  2. Revoke their personal SSH key from any servers they had access to
  3. Rotate any shared credentials they had access to (DB passwords, API keys)
  4. Remove them from the shared password manager

Step 3 is the one people skip. Don’t skip step 3.


Scenario 3: Big Organization

You’ve got multiple teams, multiple environments, compliance requirements, and an audit coming up next quarter. Welcome to enterprise secrets management. It’s exactly as fun as it sounds.

Dedicated Secrets Managers Are Non-Negotiable

At this scale, you need a proper secrets manager:

  • HashiCorp Vault — the gold standard for on-premise/multi-cloud
  • AWS Secrets Manager — if you’re AWS-native, it’s excellent
  • Azure Key Vault — same deal for Azure shops
  • Doppler or Infisical — modern SaaS options with great DX

These give you:

  • Centralized access control (RBAC)
  • Secret rotation (automatic or scheduled)
  • Full audit logs (who accessed what, when)
  • Short-lived credentials (tokens that expire)

Ansible Vault at Scale

Ansible Vault still works at scale, but you wire it to your secrets manager instead of a local file:

# Use a script that fetches from AWS Secrets Manager as the vault password source
ansible-playbook playbook.yml --vault-password-file scripts/get-vault-password.sh

Where get-vault-password.sh does something like:

#!/bin/bash
aws secretsmanager get-secret-value \
  --secret-id "ansible/vault-password" \
  --query SecretString \
  --output text

Now the vault password itself is protected by IAM. Nobody can decrypt your Ansible secrets without the right AWS permissions. Beautiful.

CI/CD at Scale: GitHub Actions + Secrets

For GitHub Actions, secrets are stored at the repo or environment level:

# .github/workflows/deploy.yml
- name: Deploy to staging
  uses: appleboy/ssh-action@v1.0.3
  with:
    host: ${{ secrets.STAGING_HOST }}
    username: ${{ secrets.STAGING_USER }}
    key: ${{ secrets.STAGING_SSH_KEY }}
    script: /home/forge/deploy.sh

The STAGING_SSH_KEY here is the private key of a dedicated CI/CD keypair. Its public key is in ~/.ssh/authorized_keys on the server. When an engineer leaves, you rotate this key pair — not your personal keys.

For production deployments, use GitHub Environments with required reviewers:

deploy-prod:
  environment: production  # Requires approval from designated reviewers
  needs: deploy-staging

This means nobody — not even someone with repo write access — can deploy to production without a human approving it. That’s the kind of thing that saves jobs.


The Golden Rules

Let’s wrap this up with the rules that apply regardless of your team size:

RuleWhy
Never commit secrets to gitRotation after exposure is a nightmare
One key per purposeIf it’s compromised, blast radius is minimal
Personal keys stay on your machineAlways
Rotate credentials when someone leavesDon’t be the company that doesn’t do this
Use short-lived tokens where possibleExpiry is free rotation
Audit who has access to whatYou can’t protect what you can’t see
Store the vault password somewhere secure, not in the repoObvious in hindsight, disaster in practice

Quick Reference

Solo developer:

# Encrypt a secret
ansible-vault encrypt_string 'my-secret' --name 'var_name'

# Run playbook with vault
ansible-playbook playbook.yml --ask-vault-pass

# Generate a deploy key
ssh-keygen -t ed25519 -f ~/.ssh/project_deploy -N "" -C "deploy@project"

Small team checklist:

  • Vault password in shared password manager
  • One deploy key per server/repo combination
  • CI secrets stored in GitHub Secrets, not in code
  • Offboarding protocol documented
  • .gitignore includes all key files and password files

Big org checklist:

  • HashiCorp Vault / AWS Secrets Manager / equivalent set up
  • Vault password fetched from secrets manager at runtime
  • Production environment has required reviewers
  • Audit logging enabled
  • Automatic secret rotation configured for critical credentials

Security doesn’t have to be complicated. It just has to be intentional.

Now go rotate that password you’ve had since 2021. You know the one.

// Comments