Secure Password Maker for Developers: CI/CD, .env, and Secrets
Developer-focused guide to generating and managing passwords for technical environments.
Introduction
Developers face unique password challenges: API keys, database credentials, environment variables, SSH keys, and CI/CD secrets. This guide covers best practices for generating and managing passwords in technical environments, with practical examples and security recommendations.
Developer-Specific Password Needs
Types of Credentials
- Database passwords (PostgreSQL, MySQL, MongoDB)
- API keys and tokens (REST APIs, GraphQL)
- Environment variables (.env files)
- SSH keys and passphrases
- CI/CD secrets (GitHub Actions, GitLab CI)
- Service account passwords
- Encryption keys
- JWT secrets
Each requires different security considerations.
Database Passwords
Requirements
- High entropy (100+ bits)
- No special characters that break connection strings
- Long enough for brute force resistance
- Rotatable without downtime
Generation
Use our Strong Password Generator with these settings:
- Length: 32+ characters
- Character types: Alphanumeric + safe symbols
- Exclude: Quotes, backticks, backslashes
Example
# Good database password
DB_PASSWORD="K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7"
# Connection string
postgresql://user:K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7@localhost:5432/mydb
Storage
Never hardcode:
// ❌ NEVER DO THIS
const password = "K9mL2pQ7nR4vXt8Y";
Use environment variables:
// ✅ Good
const password = process.env.DB_PASSWORD;
Use secrets management:
// ✅ Better
const password = await secretsManager.getSecret('db-password');
API Keys and Tokens
Generation Best Practices
Length: 32-64 characters
Format: Alphanumeric or Base64
Prefix: Identify key type (e.g., sk_live_...)
Example Generation
# Generate 32-byte random key
openssl rand -base64 32
# Output: K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7Gt4=
Or use our Strong Password Generator for instant generation.
API Key Format
# Stripe-style
sk_live_K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9M
# GitHub-style
ghp_K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7
# Custom format
api_prod_K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9M
Storage in Code
// ❌ Never commit to Git
const API_KEY = "sk_live_K9mL2pQ7nR4vXt8Y";
// ✅ Use environment variables
const API_KEY = process.env.API_KEY;
// ✅ Use secrets manager
const API_KEY = await getSecret('api-key');
Environment Variables (.env)
.env File Structure
# .env file
DB_HOST=localhost
DB_PORT=5432
DB_USER=myapp
DB_PASSWORD=K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7
API_KEY=sk_live_Xt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7Gt4Lp8
JWT_SECRET=Bw6Jq1Fp5Hd9Mk2Ns7Gt4Lp8Qr9Vx2Yz5
ENCRYPTION_KEY=Fp5Hd9Mk2Ns7Gt4Lp8Qr9Vx2Yz5Cw7Dx3
Security Rules
- Never commit .env to Git
# .gitignore
.env
.env.local
.env.*.local
- Use .env.example for documentation
# .env.example (safe to commit)
DB_HOST=localhost
DB_PORT=5432
DB_USER=
DB_PASSWORD=
API_KEY=
JWT_SECRET=
- Generate unique passwords per environment
# Development
DB_PASSWORD=K9mL2pQ7nR4vXt8Y
# Staging
DB_PASSWORD=Xt8Yz3Bw6Jq1Fp5H
# Production
DB_PASSWORD=Bw6Jq1Fp5Hd9Mk2N
CI/CD Secrets
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: |
./deploy.sh
Adding Secrets
# GitHub CLI
gh secret set DB_PASSWORD
# Enter password when prompted (use our generator)
K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7
GitLab CI
# .gitlab-ci.yml
deploy:
script:
- echo $DB_PASSWORD
only:
- main
Add secrets in GitLab UI: Settings → CI/CD → Variables
Best Practices
- ✅ Use separate secrets per environment
- ✅ Rotate secrets regularly
- ✅ Limit secret access by branch
- ✅ Audit secret usage
- ❌ Never echo secrets in logs
SSH Keys and Passphrases
Generate SSH Key
# Generate ED25519 key (recommended)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Enter passphrase when prompted
Passphrase Requirements
For SSH keys: Use a passphrase or long random password
Passphrase example:
correct horse battery staple mountain
Random password example (from our generator):
K9#mL2$pQ7@nR4!vXt8&Yz3*
SSH Config
# ~/.ssh/config
Host production
HostName prod.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
JWT Secrets
Generation
Minimum: 256 bits (32 bytes)
# Generate JWT secret
openssl rand -base64 32
# Output
K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7Gt4=
Usage in Node.js
const jwt = require('jsonwebtoken');
// ❌ Weak secret
const secret = 'mysecret';
// ✅ Strong secret from environment
const secret = process.env.JWT_SECRET;
// Sign token
const token = jwt.sign({ userId: 123 }, secret, {
expiresIn: '1h'
});
// Verify token
const decoded = jwt.verify(token, secret);
Rotation Strategy
// Support multiple secrets for rotation
const secrets = [
process.env.JWT_SECRET_CURRENT,
process.env.JWT_SECRET_PREVIOUS
];
function verifyToken(token) {
for (const secret of secrets) {
try {
return jwt.verify(token, secret);
} catch (err) {
continue;
}
}
throw new Error('Invalid token');
}
Encryption Keys
Symmetric Encryption
AES-256 requires: 256 bits (32 bytes)
# Generate encryption key
openssl rand -hex 32
# Output (64 hex characters = 32 bytes)
K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9Mk2Ns7Gt4Lp8Qr9Vx2Yz5Cw7Dx3
Usage in Python
from cryptography.fernet import Fernet
import os
# ❌ Never hardcode
key = b'K9mL2pQ7nR4vXt8Yz3Bw6Jq1Fp5Hd9M='
# ✅ Use environment variable
key = os.environ['ENCRYPTION_KEY'].encode()
# Encrypt
f = Fernet(key)
encrypted = f.encrypt(b"Secret data")
# Decrypt
decrypted = f.decrypt(encrypted)
Secrets Management Tools
HashiCorp Vault
# Store secret
vault kv put secret/db password=K9mL2pQ7nR4vXt8Y
# Retrieve secret
vault kv get secret/db
AWS Secrets Manager
const AWS = require('aws-sdk');
const client = new AWS.SecretsManager();
async function getSecret(secretName) {
const data = await client.getSecretValue({
SecretId: secretName
}).promise();
return JSON.parse(data.SecretString);
}
// Usage
const dbPassword = await getSecret('prod/db/password');
Azure Key Vault
var client = new SecretClient(
new Uri("https://myvault.vault.azure.net/"),
new DefaultAzureCredential()
);
KeyVaultSecret secret = await client.GetSecretAsync("db-password");
string password = secret.Value;
Docker and Kubernetes
Docker Secrets
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp
secrets:
- db_password
secrets:
db_password:
external: true
# Create secret
echo "K9mL2pQ7nR4vXt8Y" | docker secret create db_password -
Kubernetes Secrets
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
password: SzltTDJwUTduUjR2WHQ4WQ== # base64 encoded
# Create secret
kubectl create secret generic db-credentials \
--from-literal=password=K9mL2pQ7nR4vXt8Y
Password Rotation
Automated Rotation
// Example rotation script
async function rotatePassword() {
// Generate new password
const newPassword = generateSecurePassword(32);
// Update database
await updateDatabasePassword(newPassword);
// Update secrets manager
await secretsManager.updateSecret('db-password', newPassword);
// Update application config
await updateAppConfig({ DB_PASSWORD: newPassword });
// Restart application
await restartApp();
console.log('Password rotated successfully');
}
Rotation Schedule
- Development: As needed
- Staging: Monthly
- Production: Quarterly or after incidents
Learn more about password rotation.
Security Best Practices
1. Never Commit Secrets
# Use git-secrets to prevent commits
git secrets --install
git secrets --register-aws
2. Use Different Passwords Per Environment
Development: K9mL2pQ7nR4vXt8Y
Staging: Xt8Yz3Bw6Jq1Fp5H
Production: Bw6Jq1Fp5Hd9Mk2N
3. Implement Least Privilege
-- Create read-only user
CREATE USER readonly WITH PASSWORD 'K9mL2pQ7nR4vXt8Y';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
-- Create write user
CREATE USER writeuser WITH PASSWORD 'Xt8Yz3Bw6Jq1Fp5H';
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO writeuser;
4. Audit Secret Access
// Log secret access
function getSecret(name) {
logger.info(`Secret accessed: ${name}`, {
user: getCurrentUser(),
timestamp: new Date(),
ip: getClientIP()
});
return secretsManager.getSecret(name);
}
5. Enable MFA for Production
Require 2FA for:
- Production database access
- Cloud provider consoles
- Secrets management systems
- CI/CD platforms
Common Developer Mistakes
❌ Mistake 1: Hardcoding Credentials
// ❌ Never do this
const db = new Database({
host: 'localhost',
user: 'admin',
password: 'K9mL2pQ7nR4vXt8Y'
});
❌ Mistake 2: Committing .env Files
# ❌ Committed to Git
.env
# ✅ Add to .gitignore
echo ".env" >> .gitignore
❌ Mistake 3: Using Weak Passwords in Development
// ❌ Weak dev password
DB_PASSWORD=password123
// ✅ Strong password even in dev
DB_PASSWORD=K9mL2pQ7nR4vXt8Y
❌ Mistake 4: Logging Secrets
// ❌ Logs password
console.log('Connecting with password:', password);
// ✅ Redact sensitive data
console.log('Connecting with password: [REDACTED]');
❌ Mistake 5: Sharing Secrets via Chat
// ❌ Slack message
"Hey, the prod DB password is K9mL2pQ7nR4vXt8Y"
// ✅ Use secure sharing
"I've added the prod DB password to Vault under prod/db/password"
Tools for Developers
Password Generation
- Our tool: Strong Password Generator
- Command line:
openssl rand -base64 32 - Node.js:
crypto.randomBytes(32).toString('base64') - Python:
secrets.token_urlsafe(32)
Secrets Management
- HashiCorp Vault: Enterprise secrets management
- AWS Secrets Manager: Cloud-native secrets
- 1Password CLI: Developer-friendly password manager
- Doppler: Modern secrets management
Security Scanning
- git-secrets: Prevent committing secrets
- truffleHog: Find secrets in Git history
- detect-secrets: Pre-commit hook for secrets
- GitGuardian: Automated secret detection
Testing and Development
Local Development
# .env.local (not committed)
DB_PASSWORD=K9mL2pQ7nR4vXt8Y
API_KEY=dev_Xt8Yz3Bw6Jq1Fp5H
Testing
// Use test credentials
const testConfig = {
db: {
password: process.env.TEST_DB_PASSWORD || 'test_K9mL2pQ7nR4vXt8Y'
}
};
Mock Secrets in Tests
// Mock secrets manager
jest.mock('./secrets', () => ({
getSecret: jest.fn().mockResolvedValue('mock_password')
}));
Compliance and Auditing
PCI DSS Requirements
- Minimum 7 characters (recommend 16+)
- Mix of character types
- Change every 90 days (outdated, see rotation guide)
- Encrypt stored passwords
SOC 2 Requirements
- Document password policies
- Implement access controls
- Audit secret access
- Rotate credentials regularly
GDPR Considerations
- Encrypt passwords at rest
- Implement right to deletion
- Log access to personal data
- Use strong encryption
Conclusion
Developer password security requires:
✅ High entropy: 32+ characters for critical systems
✅ Proper storage: Environment variables or secrets managers
✅ Never commit: Use .gitignore and git-secrets
✅ Rotate regularly: Automate rotation where possible
✅ Audit access: Log who accesses what
✅ Use tools: Password managers and secrets managers
Ready to generate secure passwords for your development needs? Use our Strong Password Generator to create cryptographically secure passwords instantly.
Related Reading
Ready to Create a Strong Password?
Use our free Strong Password Generator to create secure passwords instantly.
Related Articles
Do Websites Store My Passwords? What Really Happens on the Backend
Understand how websites should (and shouldn't) store your passwords.
API Keys and Tokens: Developer's Guide to Credential Security
Essential security practices for managing API keys, access tokens, and developer credentials.
Password Hashing Algorithms Explained: bcrypt, Argon2, and More
Understand how websites securely store passwords using hashing algorithms and why it matters for your security.