Secrets management sai cách = DB password leak GitHub, AWS bill bùng nổ vì key bị steal. Bài này đi qua từ .env cơ bản đến Vault production-grade.
.env — đủ cho dev
# .env.local (gitignored)
DATABASE_URL=postgres://localhost/dev
JWT_SECRET=dev-only-secret-replace-in-prod
SENDGRID_API_KEY=SG.test-key
import 'dotenv/config'
const dbUrl = process.env.DATABASE_URL
Quan trọng: .env LUÔN trong .gitignore. Commit accident → secret leak GitHub → scan bot scrape trong giây. Nếu lỡ commit, ROTATE secret ngay, không chỉ git rm.
HashiCorp Vault — chuẩn enterprise
npm install node-vault
import vault from 'node-vault'
const client = vault({
endpoint: 'https://vault.alodev.vn',
token: process.env.VAULT_TOKEN, // service account token
})
// Lấy secret
const { data } = await client.read('secret/data/alodev/database')
const dbPassword = data.data.password
Vault feature:
- Encryption at rest (AES-256-GCM)
- Audit log mọi access
- Dynamic secret (Vault tạo DB user temporary, expire 1h)
- Auto-rotation
- ACL chi tiết theo path
- Multi-tenant
Setup phức tạp — phù hợp team có DevOps dedicated.
AWS Secrets Manager
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
const sm = new SecretsManagerClient({ region: 'ap-southeast-1' })
const { SecretString } = await sm.send(new GetSecretValueCommand({
SecretId: 'alodev/production/database',
}))
const { username, password, host } = JSON.parse(SecretString)
Lợi: rotation tự động (Lambda function rotate password DB), pricing $0.40/secret/month, IAM-based ACL. Phù hợp app trên AWS.
Google Secret Manager
import { SecretManagerServiceClient } from '@google-cloud/secret-manager'
const client = new SecretManagerServiceClient()
const [version] = await client.accessSecretVersion({
name: 'projects/alodev/secrets/db-password/versions/latest',
})
const password = version.payload.data.toString()
Tương tự AWS. Versioned (rollback được). $0.06/secret/version/month.
Kubernetes — Sealed Secrets
# Cài controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.26.2/controller.yaml
# Tạo secret normal
kubectl create secret generic db-pass --from-literal=password=secret123 --dry-run=client -o yaml > secret.yaml
# Encrypt với public key của cluster
kubeseal --controller-namespace kube-system --controller-name sealed-secrets-controller -o yaml < secret.yaml > sealed-secret.yaml
# Commit sealed-secret.yaml vào Git an toàn
git add sealed-secret.yaml && git commit -m "Add db secret"
# Apply — controller decrypt
kubectl apply -f sealed-secret.yaml
GitOps workflow: secret encrypt commit Git, chỉ controller cluster decrypt được. Không bao giờ plaintext secret tới repo.
Secret trong CI/CD
# GitHub Actions
- name: Deploy
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
run: npm run deploy
GitHub encrypted secrets — không log, không expose qua API. Nếu PR từ fork: secret KHÔNG inject (security feature).
Tốt hơn: dùng OIDC để mint short-lived token thay long-lived secret (chi tiết ở CI/CD GitHub Actions).
Rotation tự động
Tier 1 (critical): rotate 7-30 ngày
- DB master password
- API key payment
- Encryption key
Tier 2 (high): rotate 30-90 ngày
- JWT secret
- SendGrid/Mailgun API key
- Internal service token
Tier 3 (low): rotate 90-180 ngày
- GA tracking ID
- Public widget key
Checklist secrets management
- ✅ .env trong .gitignore + .gitignore audit
- ✅ Production secret KHÔNG có .env, dùng secret manager
- ✅ Rotation schedule theo tier
- ✅ Audit log mọi access secret + alert anomaly
- ✅ Pre-commit hook (gitleaks, trufflehog) detect secret accident commit
- ✅ Compromised secret response plan (rotate playbook)
- ✅ Least privilege: app chỉ access secret nó cần
Kết luận
Secrets management không complicated nhưng phải kỷ luật từ ngày 1. Setup Vault/AWS Secrets Manager đầu tư 1-2 ngày, lợi ích lâu dài. Đừng đợi đến lúc bị leak mới rút kinh nghiệm. Tham khảo Password hashing cho việc xử lý 1 loại secret cụ thể.