Runbook de Rotación de Secretos
Runbook para rotar secretos sin downtime: inventario, rotación dual-key, AWS Secrets Manager, Vault, claves JWT y emergencias.
Overview
Una contraseña de base de datos que lleva 400 días sin cambiar es un incidente esperando fecha y hora. Cuando un secreto se filtra — subido a git, pegado en un chat, olvidado por un contratista que ya no está — la respuesta es siempre la misma: rotarlo rápido, sin tirar producción. Este runbook cubre ese procedimiento de principio a fin: montar el inventario, rotar sin downtime, automatizar la rotación en AWS Secrets Manager y HashiCorp Vault, gestionar las claves de firma JWT y ejecutar una rotación de emergencia bajo presión.
Para las decisiones de estrategia y herramientas detrás de estos procedimientos, consulta la Guía Completa de Gestión de Secretos.
1. Inventario de Secretos
La rotación falla cuando no sabes qué existe. Los equipos descubren con regularidad una API key hardcodeada en un servicio heredado solo después de que la credencial filtrada aparezca en un dump de brechas. Antes de rotar nada, construye un inventario completo de cada secreto, su responsable y su fecha límite de rotación.
1.1 Tipos de Secretos
| Tipo de secreto | Frecuencia de rotación | Almacenamiento |
|---|---|---|
| Contraseñas de base de datos | 90 días | Secrets Manager / Vault |
| API keys (terceros) | 90 días | Secrets Manager / Vault |
| Claves de firma JWT | 30 días | Secrets Manager / Vault |
| Certificados TLS | 90 días antes de expirar | ACM / cert-manager |
| Claves de cifrado (KMS) | 365 días | AWS KMS / Vault Transit |
| Tokens de service account | 30 días | Secrets Manager / Vault |
| Claves SSH | 180 días | Vault SSH CA |
| Secretos de cliente OAuth | 90 días | Secrets Manager / Vault |
Las frecuencias anteriores son un punto de partida razonable, no una regla universal. Los secretos de alto valor — credenciales de bases de datos de producción, claves de firma, cualquier cosa que pueda mover dinero — merecen ventanas más cortas. NIST SP 800-57 vincula la duración del criptoperíodo a la sensibilidad de los datos protegidos; una base de 90 días para credenciales y 30 días para claves de firma es un punto intermedio defendible que la mayoría de los marcos de cumplimiento aceptan.
1.2 Plantilla de Inventario
| Secret ID | Tipo | Servicio | Responsable | Última rotación | Próxima rotación |
|---|---|---|---|---|---|
| db-prod-pg01 | Contraseña BD | payment-service | team-payments | 2026-04-01 | 2026-07-01 |
| api-stripe | API key | billing-service | team-billing | 2026-05-15 | 2026-08-15 |
| jwt-signing | Clave JWT | auth-service | team-auth | 2026-06-01 | 2026-07-01 |
| tls-api-prod | Cert. TLS | api-gateway | team-infra | 2026-03-01 | 2026-06-01 |
Una versión CSV lista para rellenar de este inventario está incluida en los recursos companion.
Cada fila necesita un responsable — un equipo, no una persona. Los secretos huérfanos son los que se olvidan hasta que un auditor o un atacante los encuentra. La columna Próxima rotación alimenta tu alerting: cualquier cosa vencida debería paginar al equipo responsable, no quedarse callada en una hoja de cálculo. La Plantilla de Rotación de Secretos ofrece una versión lista para copiar de este inventario, y la Plantilla de Calendario de Rotación de Secretos cubre la parte del calendario.
2. Estrategia de Rotación sin Downtime
El enfoque ingenuo — generar una contraseña nueva, actualizarla en todas partes, reiniciar — produce una ventana de caída donde las instancias antiguas conservan el secreto viejo y las nuevas tienen el nuevo. La rotación sin downtime evita esa ventana permitiendo que ambos secretos coexistan durante la transición.
2.1 Rotación Dual-Key
Fase 1 — Añadir el nuevo secreto (sin retirar nada)
- Generar el nuevo secreto (v2)
- Guardar v2 en el secrets manager junto a v1
- Desplegar la aplicación con soporte para v1 y v2
- La aplicación lee v2 para operaciones nuevas y acepta v1 para las existentes
Fase 2 — Cambiar al nuevo secreto
- Desplegar la aplicación para usar v2 como primaria
- Monitorizar errores y fallos de autenticación
- Esperar 24-48 horas de estabilidad
Fase 3 — Retirar el secreto antiguo
- Verificar que ningún servicio sigue usando v1
- Eliminar v1 del secrets manager
- Registrar la rotación completada en el audit trail
La ventana de estabilidad de 24-48 horas de la Fase 2 no es opcional — es donde se detectan el cron que solo corre de noche, el worker batch que se autentica semanalmente y la integración que nadie documentó. Eliminar v1 antes de tiempo es la causa más común de caídas de rotación autoinfligidas. Si algo sigue usando v1 cuando la retiras, acabas de fabricarte un incidente.
2.2 Rotación de Contraseña de Base de Datos
import boto3
import json
import psycopg2
import secrets
from datetime import datetime, timezone
from psycopg2 import sql
def rotate_database_password(secret_id: str):
client = boto3.client('secretsmanager')
# Paso 1: obtener el secreto actual
current = client.get_secret_value(SecretId=secret_id)
current_creds = json.loads(current['SecretString'])
# Paso 2: generar la nueva contraseña
new_password = secrets.token_urlsafe(32)
# Paso 3: conectar a la base de datos con las credenciales actuales
conn = psycopg2.connect(
host=current_creds['host'],
user=current_creds['username'],
password=current_creds['password'],
database=current_creds['dbname'],
)
# Paso 4: actualizar la contraseña en la base de datos (ALTER USER)
with conn.cursor() as cur:
cur.execute(
sql.SQL("ALTER USER {} WITH PASSWORD %s").format(
sql.Identifier(current_creds['username'])
),
(new_password,),
)
conn.commit()
conn.close()
# Paso 5: actualizar el secreto en Secrets Manager
new_creds = current_creds.copy()
new_creds['password'] = new_password
client.put_secret_value(
SecretId=secret_id,
SecretString=json.dumps(new_creds),
)
# Paso 6: verificar que las nuevas credenciales funcionan
conn = psycopg2.connect(
host=new_creds['host'],
user=new_creds['username'],
password=new_password,
database=new_creds['dbname'],
)
conn.close()
print(f"Rotación completada para {secret_id} a las {datetime.now(timezone.utc)}")
Aquí importan dos detalles. El paso 4 usa psycopg2.sql.Identifier en lugar de interpolación con f-string — los identificadores no se pueden parametrizar, y en un runbook de seguridad no se modela la versión insegura. El paso 6 no es decorativo: verifica que las nuevas credenciales conectan de verdad antes de declarar victoria. Una rotación que actualiza el secrets manager pero deja una contraseña rota es peor que no rotar.
3. Rotación Automática en AWS Secrets Manager
Secrets Manager rota en un calendario a través de una función Lambda que tú proporcionas. La ruta de rotación gestionada cubre la mayoría de credenciales de RDS, Redshift y DocumentDB sin código a medida; todo lo demás necesita una función de rotación.
3.1 Configurar la Rotación
import boto3
client = boto3.client('secretsmanager')
# Activar la rotación automática — cada 90 días
client.rotate_secret(
SecretId='prod/payment-service/db-credentials',
RotationLambdaARN='arn:aws:lambda:us-east-1:123456789012:function:secrets-rotation',
RotationRules={
'AutomaticallyAfterDays': 90,
},
)
# Lanzar una rotación inmediata (para pruebas o emergencias)
client.rotate_secret(
SecretId='prod/payment-service/db-credentials',
RotateImmediately=True,
)
Para bases de datos RDS, prefiere la estrategia de usuarios alternados sobre la de usuario único mostrada aquí. AWS mantiene dos cuentas de usuario (user y user_clone) y alterna cuál está activa, de modo que la aplicación nunca pierde conectividad en mitad de la rotación. La estrategia de usuario único funciona, pero introduce una ventana breve donde la contraseña antigua ya no vale y la nueva aún no está activa.
3.2 Función Lambda de Rotación
AWS llama a la función una vez por paso: createSecret, setSecret, testSecret, finishSecret. El contrato es estricto — cada paso es idempotente y Secrets Manager puede reintentarlo.
import boto3
import json
import secrets
import psycopg2
from psycopg2 import sql
def lambda_handler(event, context):
secret_arn = event['SecretId']
token = event['ClientRequestToken']
step = event['Step']
client = boto3.client('secretsmanager')
if step == 'createSecret':
# Generar una nueva versión del secreto
current = json.loads(client.get_secret_value(SecretId=secret_arn)['SecretString'])
new_password = secrets.token_urlsafe(32)
new_secret = {**current, 'password': new_password}
client.put_secret_value(
SecretId=secret_arn,
ClientRequestToken=token,
SecretString=json.dumps(new_secret),
)
elif step == 'setSecret':
# Actualizar la base de datos con la nueva contraseña
pending = client.get_secret_value(
SecretId=secret_arn,
VersionStage='AWSPENDING',
VersionId=token,
)
pending_creds = json.loads(pending['SecretString'])
current = json.loads(client.get_secret_value(SecretId=secret_arn)['SecretString'])
conn = psycopg2.connect(
host=current['host'],
user=current['username'],
password=current['password'],
)
with conn.cursor() as cur:
cur.execute(
sql.SQL("ALTER USER {} WITH PASSWORD %s").format(
sql.Identifier(pending_creds['username'])
),
(pending_creds['password'],),
)
conn.commit()
conn.close()
elif step == 'testSecret':
# Probar las nuevas credenciales
pending = client.get_secret_value(
SecretId=secret_arn,
VersionStage='AWSPENDING',
VersionId=token,
)
creds = json.loads(pending['SecretString'])
conn = psycopg2.connect(
host=creds['host'],
user=creds['username'],
password=creds['password'],
)
conn.close()
elif step == 'finishSecret':
# Promover AWSPENDING a AWSCURRENT — localizar primero el id de la versión actual
versions = client.describe_secret(SecretId=secret_arn)['VersionIdsToStages']
current_version_id = next(
vid for vid, stages in versions.items() if 'AWSCURRENT' in stages
)
client.update_secret_version_stage(
SecretId=secret_arn,
VersionStage='AWSCURRENT',
MoveToVersionId=token,
RemoveFromVersionId=current_version_id,
)
El paso finishSecret busca la versión actual con describe_secret porque el evento de rotación solo lleva SecretId, ClientRequestToken y Step — leer event['CurrentVersionId'] lanzaría un KeyError y mataría la rotación en el último paso. Además, psycopg2 no está en el runtime de Lambda; empaquétalo como capa Lambda o usa psycopg2-binary en el bundle de despliegue.
4. Rotación en HashiCorp Vault
Vault enfoca el problema de otra forma: en lugar de rotar una credencial estática compartida, emite credenciales dinámicas de vida corta por petición. Una credencial filtrada expira sola dentro de su TTL — lo que reduce drásticamente el radio de impacto de cualquier filtración. Para los detalles de implementación, consulta la receta de Credenciales Dinámicas con Vault.
4.1 Motor de Secretos de Base de Datos
# Activar el motor de secretos de base de datos
vault secrets enable database
# Configurar la conexión PostgreSQL — sacar la contraseña de admin del entorno,
# nunca pegar una credencial literal en la configuración
vault write database/config/payment-postgres \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@db-prod:5432/payment?sslmode=require" \
allowed_roles="payment-service" \
username="vault-admin" \
password="$VAULT_DB_ADMIN_PASSWORD"
# Crear un rol con rotación
vault write database/roles/payment-service \
db_name=payment-postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"
# La aplicación pide credenciales (auto-rotadas)
vault read database/creds/payment-service
# Devuelve: username=v-token-payment-123, password=generado, lease_duration=1h
Con secretos dinámicos, “rotar” deja de ser un procedimiento programado — cada renovación de lease es una rotación. El trabajo operativo se traslada a renovación y revocación: las aplicaciones deben tolerar la expiración de credenciales con elegancia, y tienes que poder revocar un prefijo de leases (vault lease revoke -prefix database/creds/payment-service) para invalidar de golpe toda una clase de credenciales filtradas.
4.2 Rotación de Claves Transit
# Crear la clave de cifrado
vault write -f transit/keys/payments
# Rotar la clave (crea una versión nueva; la anterior sigue descifrando)
vault write -f transit/keys/payments/rotate
# Listar las versiones de la clave
vault read transit/keys/payments
# latest_version: 2
# Cifrar con la versión más reciente
vault write transit/encrypt/payments plaintext=$(base64 <<< "datos sensibles")
# Descifrar (usa automáticamente la versión correcta)
vault write transit/decrypt/payments ciphertext=vault:v2:...
Las claves Transit versionan de forma nativa — el ciphertext vault:v2: le indica a Vault qué versión usar para descifrar, así que los datos antiguos siguen siendo legibles tras la rotación. Fija min_decryption_version para cortar las versiones viejas una vez que hayas recifrado el ciphertext heredado, o arrastrarás claves débiles para siempre.
5. Rotación de Claves de Firma JWT
Las claves JWT necesitan el tratamiento dual-key con un matiz extra: el header kid (key ID) indica a los verificadores qué clave firmó cada token. Durante la rotación, ambas claves deben estar publicadas — normalmente a través de un endpoint JWKS — hasta que expire el último token v1.
5.1 Estrategia Dual-Key
import jwt
from datetime import datetime, timedelta, timezone
# Claves de firma actual y nueva
SIGNING_KEYS = {
'v1': load_private_key('jwt-signing-v1'),
'v2': load_private_key('jwt-signing-v2'),
}
CURRENT_VERSION = 'v2'
# Emitir tokens con la clave actual
def issue_token(user_id: str) -> str:
payload = {
'sub': user_id,
'exp': datetime.now(timezone.utc) + timedelta(hours=1),
'iat': datetime.now(timezone.utc),
}
return jwt.encode(
payload,
SIGNING_KEYS[CURRENT_VERSION],
algorithm='RS256',
headers={'kid': CURRENT_VERSION},
)
# Verificar tokens — aceptar v1 y v2 durante la transición
def verify_token(token: str) -> dict:
# kid vive en el header JOSE, no en el payload
kid = jwt.get_unverified_header(token).get('kid', 'v1')
if kid not in SIGNING_KEYS:
raise ValueError(f"Key ID desconocido: {kid}")
public_key = get_public_key(SIGNING_KEYS[kid])
return jwt.decode(token, public_key, algorithms=['RS256'])
El kid es un parámetro del header JOSE, no un claim del payload — léelo con jwt.get_unverified_header(), no decodificando el payload. Los tokens emitidos antes de tu cambio llevaban el kid solo en el header, y buscarlo en el payload es como ocurren los fallos de verificación “misteriosos” durante rotaciones reales. La ventana de solapamiento debería igualar la vida de tus tokens: con tokens de 1 hora, 24-48 horas de aceptación dual-key cubre todos los tokens vivos más un margen para clock skew.
6. Rotación de Emergencia
La rotación programada es higiene; la rotación de emergencia es respuesta a incidentes. Cuando un secreto se filtra, el reloj arranca en el descubrimiento, no cuando a ti te venga bien. Sigue tu Plantilla de Respuesta a Incidentes de Seguridad para la comunicación y la preservación de evidencia que corre en paralelo a los pasos técnicos de abajo.
6.1 Disparadores de Emergencia
| Disparador | Acción | Plazo |
|---|---|---|
| Secreto subido a git | Rotar ya, escanear el historial de git | < 1 hora |
| Secreto expuesto en logs | Rotar ya, purgar logs | < 1 hora |
| Secreto compartido por email/chat | Rotar ya | < 1 hora |
| Sospecha de brecha | Rotar todos los secretos del radio de impacto | < 4 horas |
| Salida de empleado con acceso | Rotar en 24 horas | < 24 horas |
| Notificación de brecha de un tercero | Rotar las API keys afectadas | < 24 horas |
El “radio de impacto” en esa tabla no es adorno. Una contraseña de base de datos filtrada implica rotar todos los secretos que esa credencial podía alcanzar — réplicas de lectura, usuarios de reporting, el pipeline de analítica que conecta con la misma cuenta. Acota el radio de impacto antes de empezar a rotar, o cerrarás una puerta mientras otras tres idénticas quedan abiertas.
6.2 Procedimiento de Rotación de Emergencia
- Identificar el/los secreto(s) comprometido(s) y el radio de impacto
- Generar el/los nuevo(s) secreto(s) de inmediato
- Actualizar el secrets manager con el/los nuevo(s) valor(es)
- Lanzar la recarga / reinicio de la aplicación para tomar los nuevos secretos
- Verificar que todos los servicios usan el/los nuevo(s) secreto(s)
- Revocar / invalidar el/los secreto(s) antiguo(s) en el origen (BD, proveedor API)
- Auditar los logs de acceso buscando uso indebido del/los antiguo(s)
- Documentar el incidente en el registro de incidentes de seguridad
- Notificar a los equipos y stakeholders afectados
- Programar una revisión post-incidente en 48 horas
El paso 6 es donde los equipos resbalan: rotar en el secrets manager no revoca la credencial antigua en el origen. La contraseña vieja sigue funcionando contra la base de datos hasta que la invalidas explícitamente. Rota primero, verifica que los servicios están sanos, y después revoca — en ese orden, o te quedarás fuera a mitad del incidente.
7. Monitorización y Verificación
Una rotación no termina cuando existe el nuevo secreto — termina cuando cada consumidor demuestra que funciona. Añade estas comprobaciones al propio procedimiento de rotación, no como apéndice.
Ejecuta esta checklist de verificación tras cada rotación:
- Todas las instancias de la aplicación recargaron el secreto — revisa las etiquetas de versión en Secrets Manager o los conteos de leases en Vault, no solo “sin alarmas”
- Cero errores de autenticación en los últimos N minutos por servicio
- Health checks en verde con las nuevas credenciales (conexión a BD, llamada a la API)
- Ningún servicio sigue autenticándose con el secreto antiguo — consulta el origen:
pg_stat_activitypara usuarios de BD, lista de leases de Vault, dashboards del proveedor - Entrada de audit trail escrita: quién rotó, cuándo, qué versión, referencia del ticket
Dos métricas te dicen si el programa funciona: cobertura de rotación (porcentaje de secretos del inventario dentro de su ventana de rotación — objetivo 100%, alerta en cualquier vencido) y tiempo de rotación de emergencia (del descubrimiento a la revocación completa — la cifra por la que te juzgarán tras una filtración real). Haz seguimiento de ambas por tipo de secreto; el que rotas a mano es siempre el que rompe la línea de tendencia.
8. Procedimiento de Rollback
A veces la rotación rompe un consumidor que no conocías. Decide la ruta de rollback antes de rotar, mientras no hay presión.
| Síntoma | Respuesta |
|---|---|
| Pico de fallos de auth tras la Fase 2 | Volver a v1 como primaria; mantener v2 almacenada; arreglar el consumidor que falla |
| Secreto antiguo ya revocado | Restaurar el valor de v1 en el origen si es posible; si no, rotar otra vez a una v3 nueva y desplegar el fix primero |
| Un solo servicio roto, el resto sano | Fijar ese servicio a v1 mediante una ruta de secreto específica; no hacer rollback de toda la flota |
| La Lambda de rotación falló a medias | Mirar qué paso falló en CloudWatch; la versión AWSPENDING se puede borrar y reintentar sin riesgo |
El peor escenario de rollback es descubrir que no puedes volver atrás — la credencial antigua está revocada y un consumidor crítico solo conoce v1. Ese es el argumento de la ventana de 24-48 horas de la Fase 2: seguro barato que convierte el “no se puede volver” en “detectado a tiempo”.
9. Rotación de Secretos en Kubernetes
Los objetos Secret de Kubernetes son ConfigMaps codificados en base64, no un gestor de secretos — trátalos como mecanismo de entrega, no como fuente de verdad. El patrón estándar es External Secrets Operator sincronizando desde AWS Secrets Manager o Vault hacia el clúster.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: payment-db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: payment-db-credentials
data:
- secretKey: password
remoteRef:
key: prod/payment-service/db-credentials
property: password
El refreshInterval controla la velocidad a la que una rotación se propaga — pero el Secret sincronizado solo actualiza el objeto. Los pods siguen guardando el valor antiguo hasta reiniciarse, a menos que tu aplicación vigile el archivo montado o consulte la API. Para secretos montados, kubelet actualiza el archivo en su intervalo de sincronización (minutos), y la app debe releerlo; para variables de entorno, solo un reinicio del pod toma los valores nuevos. Presupuesta un controlador de reinicio progresivo (p. ej., Reloader) o diseña las apps para recargar credenciales. Para los patrones de montaje, consulta la receta de Montaje de ConfigMaps y Secrets en Kubernetes.
10. Probar tu Rotación
Un procedimiento de rotación que nunca se ha ejecutado es una hipótesis. Pruébalo como pruebas los backups: con regularidad, contra la ruta real, antes de necesitarlo.
- Rotar un secreto de no-producción de punta a punta cada mes — mismo tooling, mismo runbook, no una “ruta de prueba” simplificada
- Matar una instancia de la app a mitad de rotación y verificar la recuperación
- Medir el tiempo desde “iniciar rotación” hasta “todos los servicios con el secreto nuevo” — esa es tu estimación real de emergencia
- Simular una Fase 2 fallida: forzar un error de auth, verificar que salta el alerting
- Ejecutar el procedimiento de emergencia completo cada trimestre como game day
La primera rotación real en producción te sorprenderá — un consumidor que olvidaste, un TTL que no recarga, un timeout de Lambda en setSecret. Mejor conocer esas sorpresas un martes por la tarde en staging que durante una brecha.
Errores Comunes
- Rotar el secreto en el gestor pero no en el origen. Secrets Manager es un almacén, no un ejecutor — la contraseña antigua sigue funcionando hasta que la base de datos o el proveedor la invalida.
- Eliminar el secreto antiguo antes de que acabe la ventana de estabilidad. El cron nocturno y el batch semanal solo aparecen cuando fallan. Espera las 24-48 horas completas.
- Leer el
kiddel payload del JWT. Es un parámetro del header; los claims del payload son para el cuerpo del token. Verifica conget_unverified_header. - Rotar sin inventario. No puedes rotar lo que no has catalogado — el inventario de la sección 1 es el prerrequisito, no papeleo.
- Hardcodear las credenciales de los propios scripts de rotación. Una Lambda que rota secretos usando una contraseña de admin embebida crea un nuevo secreto viciado para arreglar el viejo. Usa roles de IAM y referencias de entorno.
- Olvidar los consumidores cron y batch. Se autentican poco, así que fallan tarde — mucho después de que hayas dado la rotación por terminada.
- Tratar los Secrets de Kubernetes como un gestor de secretos. Base64 es codificación, no cifrado. Sincroniza desde un gestor de secretos real y restringe el RBAC sobre los objetos Secret.
Ver también
- Guía Completa de Gestión de Secretos
- Plantilla de Rotación de Secretos
- Plantilla de Respuesta a Incidentes de Seguridad
- Credenciales Dinámicas con HashiCorp Vault
- Rotación de Refresh Tokens JWT en Python
- AWS Secrets Manager — Rotación
- HashiCorp Vault — Motor de Secretos de Base de Datos
- NIST SP 800-57 — Recomendaciones de Gestión de Claves
- OWASP Secrets Management Cheat Sheet
Código companion: recursos del runbook de rotación de secretos — la Lambda de rotación, el script de rotación de base de datos, los comandos de configuración de Vault y el CSV de inventario de secretos listo para rellenar de esta página.
Preguntas frecuentes
¿Con qué frecuencia debería rotar los secretos?
Noventa días para contraseñas de bases de datos y API keys, treinta para claves de firma JWT y tokens de servicio, anualmente para claves de cifrado y antes de la expiración para certificados TLS. Trátalos como mínimos: cualquier cosa que proteja datos de pago o datos personales merece una ventana más corta, y cualquier cosa automatizada puede rotar más a menudo porque el coste marginal es cero. La restricción más dura suele ser tu capacidad de rotar sin downtime — resuelve eso primero y luego aprieta las frecuencias.
¿Qué es la rotación sin downtime y por qué importa?
La rotación sin downtime mantiene válidos el secreto antiguo y el nuevo al mismo tiempo durante una ventana de transición. La aplicación acepta ambos, cambia el uso primario al nuevo y retira el viejo tras un período de estabilidad. Sin ella, rotar obliga a un reinicio coordinado — lo que significa una caída o un congelamiento de cambios. Para cualquier cosa con SLA, el solapamiento dual-key es la única opción sensata.
¿Cómo roto secretos que están hardcodeados en el código de la aplicación?
No los rotas en el sitio — los migras primero. Mueve el valor a un secrets manager, cambia el código para que lo lea al arrancar o en runtime, despliega y luego rota a través del gestor. Escanea el repo con GitLeaks o TruffleHog buscando otras copias antes de empezar; la misma clave suele vivir en más de un archivo. Cualquier cosa que quede en el código fuente sigue comprometida por mucho que la "rotes" en otro sitio.
¿Qué hago si un secreto se sube a git por accidente?
Asume que es público en el momento en que aterriza. Rota de inmediato y luego limpia el historial con git filter-branch o BFG — pero trata la reescritura del historial como higiene, no como remediación, porque los forks y clones ya tienen el valor. Revoca la credencial antigua en su origen, revisa los logs de acceso buscando uso posterior al commit y añade el patrón a los hooks de pre-commit para que el siguiente se bloquee antes de aterrizar.
¿Cómo verifico que todos los servicios tomaron el nuevo secreto?
Comprueba el stage de versión en tu secrets manager y luego verifica en el origen: pg_stat_activity muestra qué usuarios de base de datos están conectados, Vault lista los leases activos y la mayoría de proveedores de API muestran marcas de último uso por clave. Vigila los logs de la aplicación buscando errores de auth durante toda la ventana de estabilidad — los consumidores que se autentican semanalmente son los que fallan al tercer día.
Recursos Relacionados
Checklist de Remediacion OWASP Top 10
Checklist para trackear remediacion de OWASP Top 10 vulnerabilities per application: risk assessment, fix priority, code-level remediation steps, verification testing y compliance reporting con ejemplos para cada OWASP category.
DocPlantilla de Rotación de Secretos
Plantilla para programar y rastrear la rotación de claves API, tokens y certificados.
DocPlantilla de Respuesta a Incidentes de Seguridad
Plantilla de respuesta a incidentes de seguridad: detección, clasificación, contención, erradicación, recuperación, comunicación y revisión post-incidente.
GuideGestión de Secrets
Gestionar secrets de aplicaciones de forma segura en produccion. Cubre HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, Doppler, rotacion de secrets, environment variables, rotacion zero-downtime y secrets en CI/CD pipelines con ejemplos de codigo.
RecipeCredenciales en Vivo de Base de Datos con HashiCorp Vault
Como usar HashiCorp Vault para generar credenciales de base de datos de corta duracion, eliminando passwords hardcodeados y reduciendo secret sprawl