Secrets Management for Developers


The Secrets Problem

Every application depends on secrets: API keys, database passwords, encryption keys, OAuth tokens, and TLS certificates. Mishandling these secrets is one of the most common causes of security breaches. A single hardcoded credential committed to a public repository can compromise your entire infrastructure within minutes.

Where Secrets Go Wrong

| Mistake | Consequence | |---------|-------------| | Hardcoded in source code | Credentials exposed in version control | | Stored in environment files committed to git | Accidental exposure in public repos | | Shared via chat or email | Unbounded access, no audit trail | | Stored in config files with wide permissions | Accessible to any process on the machine | | Logged during debugging | Credentials visible in log aggregation systems |

The Vault Pattern

A secrets vault is a centralized service that stores, manages, and audits access to secrets. Applications request secrets at runtime rather than reading them from configuration files.

HashiCorp Vault




# Start Vault in development mode


vault server -dev




# Store a secret


vault kv put secret/database \


host=db.example.com \


port=5432 \


username=app_user \


password=$(openssl rand -base64 32)




# Read a secret


vault kv get secret/database





Vault Integration with Application Code




import hvac




client = hvac.Client(url='https://vault.example.com',


token=get_vault_token())


secret = client.secrets.kv.read_secret_version(


path='database'


)


db_password = secret['data']['data']['password']




# Use the secret to connect


conn = psycopg2.connect(


host=secret['data']['data']['host'],


password=db_password


)





Cloud-Native Solutions

AWS Secrets Manager




import boto3


from botocore.exceptions import ClientError




def get_secret(secret_name):


client = boto3.client('secretsmanager')


response = client.get_secret_value(SecretId=secret_name)


return json.loads(response['SecretString'])




# Automatic rotation


db_creds = get_secret('prod/database/credentials')





GCP Secret Manager




from google.cloud import secretmanager




def access_secret_version(secret_id, version_id="latest"):


client = secretmanager.SecretManagerServiceClient()


name = f"projects/my-project/secrets/{secret_id}/versions/{version_id}"


response = client.access_secret_version(name=name)


return response.payload.data.decode("UTF-8")





Secrets in CI/CD

Never store secrets in repository CI/CD configuration files that are committed to source control. Use each platform's native secrets store:

| Platform | How to Store Secrets | |----------|---------------------| | GitHub Actions | Settings > Secrets and variables > Actions | | GitLab CI | Settings > CI/CD > Variables | | CircleCI | Project Settings > Environment Variables | | Jenkins | Manage Jenkins > Credentials |




# GitHub Actions workflow with secrets


name: Deploy


on: [push]


jobs:


deploy:


runs-on: ubuntu-latest


steps:


- uses: actions/checkout@v4


- name: Deploy to production


env:


DB_PASSWORD: ${{ secrets.DB_PASSWORD }}


API_KEY: ${{ secrets.API_KEY }}


run: ./deploy.sh





Detecting Secret Leaks

Pre-Commit Hooks

Use tools like `git-secrets` or `truffleHog` as pre-commit hooks:




# Install git-secrets


brew install git-secrets


git secrets --install


git secrets --register-aws




# Scan for secrets before commit


#!/bin/sh


# .git/hooks/pre-commit


git secrets --scan





Scanning Repositories




# Scan the entire history


trufflehog git https://github.com/example/repo.git




# Scan with Gitleaks


gitleaks detect --source . --verbose





Rotation and Expiration

Secrets should have a limited lifetime. Implement automatic rotation:


* **Database passwords**: Rotate every 90 days. Use zero-downtime rotation with two-password windows.

* **API keys**: Rotate immediately if compromised, regularly every 180 days.

* **TLS certificates**: Automate renewal with Let's Encrypt and cert-manager.

* **SSH keys**: Rotate on employee departure or annually.





# Example: Zero-downtime DB password rotation


# Phase 1: Update app to accept both old and new passwords


# Phase 2: Rotate master password in database


# Phase 3: Update app to use only new password


# Phase 4: Revoke old password





The Principle of Least Privilege

Secrets should be scoped to what a particular service or developer needs:


* Each microservice gets its own set of secrets, not shared credentials.

* Developers get ephemeral secrets scoped to development environments.

* Service accounts have the minimum permissions required for their function.

* Audit every secret access with timestamp and requester identity.


Summary

Treat secrets as the critical infrastructure they are. Use a dedicated secrets vault in production, store them in platform-native secret stores for CI/CD, never hardcode them or commit them to version control, and implement automatic rotation. Combine these practices with regular scanning for leaked secrets and strict access control to minimize the blast radius of any exposure.