Back to Blog
Technical12 min

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

  1. Database passwords (PostgreSQL, MySQL, MongoDB)
  2. API keys and tokens (REST APIs, GraphQL)
  3. Environment variables (.env files)
  4. SSH keys and passphrases
  5. CI/CD secrets (GitHub Actions, GitLab CI)
  6. Service account passwords
  7. Encryption keys
  8. 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

  1. Never commit .env to Git
# .gitignore
.env
.env.local
.env.*.local
  1. Use .env.example for documentation
# .env.example (safe to commit)
DB_HOST=localhost
DB_PORT=5432
DB_USER=
DB_PASSWORD=

API_KEY=
JWT_SECRET=
  1. 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.