1. Gestión de Secretos
Estrategias y herramientas para gestión segura de secretos, credenciales y configuración sensible.
1.1 🔐 Herramientas de Gestión de Secretos
1.1.1 Comparación
| Tool | Pros | Cons | Cuándo Usar |
|---|---|---|---|
| HashiCorp Vault | Flexible, audit logs, dynamic secrets | Complejidad operacional | Empresas, multi-cloud |
| AWS Secrets Manager | Integración nativa AWS, rotation automática | Lock-in AWS | Workloads en AWS |
| Azure Key Vault | Integración nativa Azure, HSM | Lock-in Azure | Workloads en Azure |
| GCP Secret Manager | Integración nativa GCP, simple | Lock-in GCP | Workloads en GCP |
| Doppler | UI amigable, multi-env | Costo | Startups, equipos pequeños |
1.1.2 HashiCorp Vault - Ejemplo
# Inicializar Vault
vault operator init
# Unsealar Vault (requiere 3 de 5 keys)
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>
# Login
vault login <root-token>
# Guardar secreto
vault kv put secret/database/config \
username=dbuser \
password=supersecret
# Leer secreto
vault kv get secret/database/config
# Crear policy (least privilege)
vault policy write app-policy - <<EOF
path "secret/data/database/config" {
capabilities = ["read"]
}
EOF
# Crear token con policy
vault token create -policy=app-policy
1.2 🔄 Rotación de Secretos
1.2.1 Por Qué Rotar Secretos
| Razón | Frecuencia Recomendada |
|---|---|
| Compliance (SOC2, PCI-DSS) | 90 días |
| Secreto comprometido | Inmediato |
| Empleado deja la empresa | Inmediato |
| Best practice | 90 días |
1.2.2 Rotación Automatizada
Ejemplo con AWS Secrets Manager:
import boto3
import json
def lambda_handler(event, context):
"""
Lambda function para rotar secreto de DB.
Triggered por AWS Secrets Manager cada 30 días.
"""
service_client = boto3.client('secretsmanager')
arn = event['SecretId']
token = event['ClientRequestToken']
step = event['Step']
if step == "createSecret":
# Generar nueva password
new_password = generate_random_password()
# Guardar en "pending" version
service_client.put_secret_value(
SecretId=arn,
ClientRequestToken=token,
SecretString=json.dumps({"password": new_password}),
VersionStages=['AWSPENDING']
)
elif step == "setSecret":
# Actualizar password en DB
pending_secret = get_secret_version(arn, "AWSPENDING")
update_database_password(pending_secret['password'])
elif step == "testSecret":
# Verificar que nueva password funciona
pending_secret = get_secret_version(arn, "AWSPENDING")
test_database_connection(pending_secret['password'])
elif step == "finishSecret":
# Marcar nueva version como "current"
service_client.update_secret_version_stage(
SecretId=arn,
VersionStage='AWSCURRENT',
MoveToVersionId=token
)
1.2.3 Rotación Sin Downtime
Estrategia:
- Crear nueva credencial (sin invalidar la vieja)
- Deployar aplicación con nueva credencial
- Verificar que funciona
- Invalidar credencial vieja
1.3 🔒 Mínimo Privilegio
1.3.1 IAM Policies (AWS)
❌ MAL (demasiado permisivo):
{
"Version": "2017",
"Statement": [{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}]
}
✅ BIEN (least privilege):
{
"Version": "2017",
"Statement": [{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789:secret:prod/database/*"
}]
}
1.3.2 Service Accounts (Kubernetes)
# Service Account con RBAC
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["database-credentials"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-secrets
subjects:
- kind: ServiceAccount
name: app-service-account
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
1.4 🚀 Secretos en CI/CD
1.4.1 GitHub Actions
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# ❌ MAL: Secreto en código
# - run: echo "PASSWORD=supersecret" >> .env
# ✅ BIEN: Secreto desde GitHub Secrets
- name: Deploy
env:
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: |
# Secretos disponibles como env vars
./deploy.sh
1.4.2 Evitar Secretos en Logs
# ❌ MAL: Secreto puede aparecer en logs
- run: echo "Connecting with password ${{ secrets.PASSWORD }}"
# ✅ BIEN: Mask secretos
- run: |
echo "::add-mask::${{ secrets.PASSWORD }}"
# Ahora el secreto será reemplazado por *** en logs
1.5 🔍 Detección de Secretos
1.5.1 Pre-Commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
1.5.2 TruffleHog
# Escanear repo completo (incluyendo historia)
trufflehog git file://. --only-verified
# Escanear solo cambios recientes
trufflehog git file://. --since-commit HEAD~10
# Escanear antes de push
git diff --staged | trufflehog --no-update
1.5.3 git-secrets
# Instalar hooks
git secrets --install
# Agregar patterns a detectar
git secrets --add 'password\s*=\s*.+'
git secrets --add 'api[_-]?key\s*=\s*.+'
git secrets --add --allowed 'example.com' # Whitelist
# Escanear
git secrets --scan
1.6 📋 Artefactos
1.6.1 Secret Management Checklist
# Secret Management Checklist
## Storage
- [ ] Secretos NO están en código
- [ ] Secretos NO están en .env commiteado
- [ ] Secretos están en secret manager (Vault, AWS Secrets Manager, etc)
- [ ] Secretos están encriptados at-rest
## Access Control
- [ ] Least privilege (solo quien necesita tiene acceso)
- [ ] Service accounts (no usar credenciales personales)
- [ ] MFA habilitado para acceso a secretos críticos
- [ ] Audit logs habilitados
## Rotation
- [ ] Secretos críticos rotan cada 90 días
- [ ] Rotation es automática (no manual)
- [ ] Zero-downtime rotation implementada
- [ ] Proceso de rotation documentado
## CI/CD
- [ ] Secretos inyectados como env vars (no hardcoded)
- [ ] Secretos masked en logs
- [ ] Secretos no persisten en artifacts
## Detection
- [ ] Pre-commit hooks configurados (detect-secrets, trufflehog)
- [ ] Escaneo periódico de repo (git-secrets)
- [ ] Alertas si secreto se detecta en código
## Incident Response
- [ ] Playbook para secreto comprometido
- [ ] Contactos de emergencia documentados
- [ ] Proceso de rotation de emergencia testeado
1.6.2 Vault Setup Guide
# HashiCorp Vault Setup Guide
## 1. Instalación
### Docker (desarrollo)
```bash
docker run -d --name=vault \
-p 8200:8200 \
--cap-add=IPC_LOCK \
vault server -dev
1.6.3 Producción (Kubernetes)
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault \
--set server.ha.enabled=true \
--set server.ha.replicas=3
1.7 2. Inicialización
# Inicializar (solo primera vez)
vault operator init -key-shares=5 -key-threshold=3
# Guardar unseal keys y root token de forma segura
# NUNCA commitear estos valores
# Unsealar (requiere 3 de 5 keys)
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>
1.8 3. Configuración
# Login
export VAULT_ADDR='http://localhost:8200'
vault login <root-token>
# Habilitar KV secrets engine
vault secrets enable -path=secret kv-v2
# Crear secreto
vault kv put secret/myapp/config \
db_password=supersecret \
api_key=abc123
1.9 4. Policies
# Crear policy para app
vault policy write myapp-policy - <<EOF
path "secret/data/myapp/*" {
capabilities = ["read"]
}
EOF
# Crear token con policy
vault token create -policy=myapp-policy
1.10 5. Integración con App
import hvac
# Conectar a Vault
client = hvac.Client(url='http://localhost:8200', token='<app-token>')
# Leer secreto
secret = client.secrets.kv.v2.read_secret_version(path='myapp/config')
db_password = secret['data']['data']['db_password']
1.10.1 Secret Leak Response Playbook
# Secret Leak Response Playbook
## Detection
**Alerta:** Secreto detectado en código / logs / público
## Immediate Actions (0-15 min)
### 1. Assess Severity
- [ ] ¿Qué secreto se expuso? (DB password, API key, etc)
- [ ] ¿Dónde se expuso? (GitHub público, logs, Slack)
- [ ] ¿Cuánto tiempo estuvo expuesto?
### 2. Revoke Secret
- [ ] Invalidar secreto inmediatamente
- [ ] Rotar a nuevo secreto
- [ ] Verificar que nuevo secreto funciona
### 3. Remove from Source
- [ ] Remover de código (git revert + force push)
- [ ] Remover de logs (si es posible)
- [ ] Remover de caches
## Investigation (60 min)
### 4. Audit Access
- [ ] Revisar audit logs (¿alguien usó el secreto?)
- [ ] Identificar accesos sospechosos
- [ ] Determinar blast radius
### 5. Assess Damage
- [ ] ¿Hubo acceso no autorizado?
- [ ] ¿Se comprometieron datos?
- [ ] ¿Se requiere notificación a usuarios/reguladores?
## Remediation (1-24 hours)
### 6. Fix Root Cause
- [ ] Implementar pre-commit hooks
- [ ] Educar al equipo
- [ ] Revisar procesos
### 7. Post-Mortem
- [ ] Escribir post-mortem
- [ ] Identificar action items
- [ ] Asignar responsables
## Communication
### Internal
- Slack #security: "Secret leak detected, investigating"
- Update cada 30 min
### External (si aplica)
- Notificar a usuarios afectados
- Notificar a reguladores (GDPR, etc)