Skip to main content

Chương 31: Secrets Management

Khái niệm

Secrets là credentials, API keys, private keys, database passwords — bất cứ thứ gì nếu bị lộ sẽ cho phép unauthorized access.

Vấn đề phổ biến:

  • Hardcode trong source code
  • Commit vào Git
  • In ra logs
  • Expose qua environment variables
  • Lưu trong container images

Secrets Scanning

# truffleHog: scan Git history cho secrets
trufflehog git file://./myrepo --only-verified

# gitleaks: scan current repo
gitleaks detect --source . --verbose

# Tìm patterns phổ biến:
grep -rn "password\s*=\s*['\"][^'\"]\+" src/
grep -rn "api_key\s*=\s*['\"][^'\"]\+" src/
grep -rn "BEGIN.*PRIVATE KEY" .
grep -rn "AKIA[0-9A-Z]{16}" . # AWS Access Key pattern

# Pre-commit hook
cat .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks

HashiCorp Vault

# Vault: secrets engine cho enterprise

# Start Vault
vault server -dev

# Store secret
vault kv put secret/myapp \
db_password="SuperSecret123" \
api_key="sk-abc123"

# Read secret
vault kv get secret/myapp

# Dynamic secrets: Vault tạo credentials tạm thời
vault secrets enable database
vault write database/config/my-db \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(localhost:3306)/" \
allowed_roles="my-role"

# Vault tạo DB credentials tạm thời (expire sau 1h)
vault read database/creds/my-role
# → username: v-root-abc123 | password: random_strong_password | lease: 1h

App đọc từ Vault:

import hvac

client = hvac.Client(url='https://vault.internal:8200')
client.auth.kubernetes.login(role='my-app', jwt=get_k8s_service_account_jwt())

# Đọc secret
secret = client.secrets.kv.v2.read_secret_version(path='myapp')
db_password = secret['data']['data']['db_password']

AWS Secrets Manager

import boto3
import json

def get_secret(secret_name: str, region: str = 'us-east-1') -> dict:
client = boto3.client('secretsmanager', region_name=region)

response = client.get_secret_value(SecretId=secret_name)

if 'SecretString' in response:
return json.loads(response['SecretString'])
else:
return json.loads(base64.b64decode(response['SecretBinary']))

# Sử dụng
secrets = get_secret('prod/myapp/database')
db_password = secrets['password']

Secret Rotation:

# AWS Secrets Manager tự động rotate với Lambda
# Không cần hardcode password — Secrets Manager handle rotation

Kubernetes External Secrets

# External Secrets Operator: sync từ AWS SM sang K8s Secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: ClusterSecretStore
target:
name: db-credentials # Tên K8s Secret được tạo
data:
- secretKey: password
remoteRef:
key: prod/myapp/database
property: password

Best Practices

1. Never commit secrets to Git (dùng pre-commit hooks)
2. Không log secrets (log sanitization)
3. Use short-lived credentials (dynamic secrets, session tokens)
4. Rotate secrets regularly
5. Principle of least privilege: mỗi app chỉ có secrets cần thiết
6. Encrypt secrets at rest và in transit
7. Audit access: ai, khi nào, secret nào
8. Revoke immediately nếu suspect compromise

Tóm tắt

  • Secrets trong source code hoặc logs = immediate breach risk.
  • Scan code và Git history thường xuyên (gitleaks, truffleHog).
  • Vault cho enterprise secrets management với dynamic credentials.
  • AWS Secrets Manager/GCP Secret Manager cho cloud-native.
  • Kubernetes: External Secrets Operator thay vì K8s Secrets cơ bản.