Gestión de secretos y configuración
Los secretos codificados en duro son el fruto más accesible de los incidentes de seguridad. Una clave API en un archivo de configuración, una contraseña de base de datos en un Docker Compose, una clave de acceso de AWS en un script de prueba — estas se confirman, se envían y se olvidan. Luego alguien bifurca el repositorio, GitHub lo indexa o se roba un laptop. Ahora su base de datos de producción es el patio de juegos de otra persona.
La solución no es complicada: no almacene secretos en el código, use un gestor de secretos, rote las credenciales regularmente. Pero llegar ahí requiere auditar lo que tiene, elegir las herramientas adecuadas y cambiar la forma en que su equipo gestiona la configuración. Este capítulo describe ese proceso.
Por qué esto importa para las empresas pequeñas
Los equipos pequeños a menudo se saltan la gestión de secretos porque "no somos un objetivo" o "lo arreglaremos más tarde." Ambas suposiciones son incorrectas.
La superficie de exposición es mayor de lo que cree. Su código base probablemente toca una docena de servicios: base de datos, proveedor de correo electrónico, pasarela de pago, análisis, almacenamiento en la nube, monitoreo, CDN. Cada integración tiene credenciales. Eso son una docena de vectores de ataque si alguna credencial se filtra.
Git nunca olvida. Eliminar un secreto del código no lo elimina del historial. Cada commit es permanente. Si envió una clave de AWS hace seis meses y la eliminó al día siguiente, sigue ahí. Los escáneres automatizados verifican el historial de Git, no solo los archivos actuales. En 2024, GitHub detectó 39 millones de filtraciones de secretos en repositorios públicos. Según el informe de GitGuardian de 2025, el 70% de los secretos filtrados en 2022 siguen activos hoy — los atacantes tienen una superficie de ataque en crecimiento.
Los equipos pequeños significan acceso compartido. Cuando cinco personas tienen acceso a las credenciales de producción a través de archivos .env compartidos o mensajes de Slack, no tiene idea de quién hizo qué cuando las cosas salen mal. Y cuando alguien se va, se supone que debe rotar todo — pero nadie lo hace.
El coste de recuperación es alto. Para una startup, un solo incidente que involucre credenciales filtradas puede significar días de limpieza: rotar cada clave expuesta, auditar los registros de acceso, notificar a los clientes si se accedió a los datos. Es tiempo que no tiene.
Incidentes del mundo real
Estos no son escenarios hipotéticos — son casos documentados.
Home Depot (2025). Home Depot dejó los sistemas internos en riesgo durante más de un año debido a un token de acceso de GitHub expuesto perteneciente a un empleado. El token proporcionaba acceso a cientos de repositorios privados que contenían sistemas críticos — infraestructura en la nube, gestión de pedidos, inventario. Una credencial filtrada, más de un año de exposición.
Exposición masiva en GitLab (2025). El ingeniero de seguridad Luke Marshall escaneó 5,6 millones de repositorios públicos de GitLab usando TruffleHog y encontró 17.430 secretos válidos — claves API, credenciales de nube, tokens de acceso. Estos afectaron a más de 2.800 dominios únicos. La mayoría de los secretos seguían activos y podían ser explotados en el momento del descubrimiento.
Ataque a la cadena de suministro GhostAction (2025). Los atacantes comprometieron 327 cuentas de GitHub y robaron 3.325 secretos de entornos CI/CD en 817 repositorios. Los datos robados incluían tokens de PyPI, tokens de npm, credenciales de DockerHub, tokens de GitHub y claves de acceso de AWS. Una acción comprometida se propagó por toda la cadena de suministro.
El problema de los 39 millones (2024). Los propios datos de GitHub muestran que 39 millones de secretos se filtraron en repositorios públicos solo en 2024. Eso no es un error — es un patrón. Los desarrolladores agregan secretos "temporalmente", se olvidan de ellos y eventualmente envían el código a repositorios públicos.
El patrón se repite constantemente. El secreto se agrega "solo para probar", sobrevive a múltiples refactorizaciones y eventualmente acaba en algún lugar público. Los escáneres automatizados lo encuentran en minutos. Para cuando se da cuenta, el daño está hecho.
Qué cuenta como un secreto
Cualquier cosa que otorgue acceso a un sistema o servicio:
| Categoría | Ejemplos |
|---|---|
| Contraseñas | Credenciales de base de datos, cuentas de administrador, contraseñas de servicio |
| Claves API y tokens | Stripe, Twilio, SendGrid, tokens de GitHub/GitLab, secretos OAuth |
| Materiales criptográficos | Claves privadas, certificados TLS, claves SSH, claves de firma JWT |
| Cadenas de conexión | URLs de base de datos con credenciales incrustadas, URIs de message broker |
| Credenciales en la nube | Claves de acceso de AWS, JSON de cuenta de servicio de GCP, cadenas de conexión de Azure |
Si no está seguro de si algo es un secreto: si le permite autenticarse o acceder a datos, es un secreto.
Dónde acaban los secretos (y no deberían)
Código fuente
El más obvio. Los desarrolladores codifican valores durante la creación de prototipos y se olvidan de eliminarlos:
# BAD: This gets committed, pushed, and indexed
db = connect(
host="db.internal",
password="Pr0d_P@ssw0rd_2024!" # TODO: fix this
)
Archivos de configuración
Menos obvio pero igual de peligroso:
# BAD: docker-compose.yml in version control
services:
api:
environment:
- STRIPE_SECRET_KEY=sk_live_4eC39HqLyjWDarjtT1zdp7dc
// BAD: config.js with real credentials
module.exports = {
database: {
password: process.env.DB_PASS || "fallback_password_123"
}
};
Ese "fallback" está ahora en su código base para siempre.
Historial de Git
Eliminó el secreto, pero:
$ git log -p --all -S "sk_live_" | head -20
commit a1b2c3d4...
- STRIPE_KEY=sk_live_4eC39HqLyjWDarjtT1zdp7dc
Cualquiera con acceso al repositorio puede encontrarlo.
Registros de CI/CD
Los registros de build a menudo hacen eco de variables de entorno o salidas de comandos:
$ ./deploy.sh
Connecting to database with password: Pr0d_P@ssw0rd_2024!
Deployment complete.
Archivos locales
Archivos .env que los desarrolladores comparten a través de Slack, Notion o correo electrónico. Sin pista de auditoría, sin control de acceso, y se proliferan por los laptops.
Código del lado del cliente
Secretos en bundles de JavaScript, binarios de aplicaciones móviles o configuración de frontend. Ya no son secretos — son públicos.
Errores comunes
Antes de adentrarse en las soluciones, aquí están los patrones que meten a los equipos en problemas. Reconocerá algunos de estos.
Secretos en archivos "de ejemplo"
# .env.example — committed to repo
DATABASE_URL=postgres://user:REAL_PASSWORD@host/db
Los archivos "de ejemplo" con valores reales siguen siendo filtraciones. Use valores obviamente falsos:
# .env.example — safe
DATABASE_URL=postgres://user:CHANGE_ME@localhost/db
Registrar secretos
# BAD
logger.info(f"Connecting with password: {password}")
# BAD
logger.debug(f"Request headers: {request.headers}") # Might include auth tokens
Nunca registre credenciales. Filtre los campos sensibles antes de registrar.
Secretos en mensajes de error
# BAD
raise ConnectionError(f"Failed to connect to {host} with password {password}")
# GOOD
raise ConnectionError(f"Failed to connect to {host}")
Confiar en el almacenamiento del lado del cliente
Las claves API en JavaScript de frontend, configuración de aplicaciones móviles o aplicaciones Electron no son secretos. Son públicos. Si necesita proteger una API, use un proxy de backend.
Compartir a través de Slack/correo electrónico
"Oye, ¿puedes enviarme la contraseña de la base de datos de producción?" → contraseña en Slack → buscable para siempre → sin pista de auditoría → sin forma de revocar.
Use el gestor de secretos. Comparta el acceso, no las credenciales.
Saltarse la rotación al dar de baja empleados
Un empleado se va → su laptop tenía acceso a archivos .env → esos secretos ahora son no controlados. Rote las credenciales cuando la gente se vaya, especialmente las cuentas con privilegios.
Patrones .gitignore faltantes
Si no ignora explícitamente los archivos de secretos, alguien eventualmente los confirmará. Agregue esto a cada repositorio:
# Environment files
.env
.env.*
!.env.example
# Secret/credential files
*.pem
*.key
*.p12
*.pfx
secrets.yml
secrets.yaml
credentials.json
*-credentials.json
service-account*.json
# IDE and tool configs that might contain secrets
.idea/**/dataSources/
.idea/**/dataSources.xml
# Terraform state (contains secrets in plain text)
*.tfstate
*.tfstate.*
.terraform/
El enfoque de gestión de secretos
Principios
1. Los secretos nunca tocan el control de versiones. No en el código, no en archivos de configuración, no en archivos "de ejemplo" con valores reales.
2. Fuente única de verdad. Un sistema almacena las credenciales. Todo lo demás las obtiene en tiempo de ejecución.
3. Acceso de mínimo privilegio. Los scripts de despliegue obtienen secretos de producción. Los laptops de los desarrolladores obtienen secretos de desarrollo. Nadie obtiene todo.
4. Audite todo. Sepa quién accedió a qué y cuándo.
5. Rote regularmente. Con o sin filtración, las credenciales deben cambiar según un calendario.
Categorías de herramientas
| Tipo | Ejemplos | Mejor para |
|---|---|---|
| Gestores de secretos dedicados | Passwork, HashiCorp Vault, AWS Secrets Manager | Infraestructura y automatización CI/CD |
| Soluciones nativas de la nube | Passwork Cloud, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault | Entornos de nube única e híbridos |
| Plataformas de variables de entorno | Doppler, Infisical | Flujos de trabajo centrados en el desarrollador |
| Gestores de contraseñas | Passwork (cubre tanto humanos como automatización) | Credenciales humanas + secretos de infraestructura en una herramienta |
Recomendamos Passwork — un gestor de contraseñas y secretos empresarial que cubre ambos lados del problema en una sola herramienta.
La mayoría de los equipos acaban manteniendo dos sistemas separados: un gestor de contraseñas para las personas y una bóveda de secretos para la infraestructura. Passwork elimina esa división. Gestiona las credenciales humanas (con bóvedas compartidas, acceso basado en roles y registros de auditoría) junto a los secretos de infraestructura (a través de API, CLI y SDKs para la automatización). Una herramienta, una pista de auditoría, una política de acceso.
Opciones de despliegue. Passwork viene como una solución on-premise — instalada en sus propios servidores, los datos nunca abandonan su infraestructura — y como una versión en la nube. Ambas utilizan la misma arquitectura de conocimiento cero: todo el cifrado ocurre del lado del cliente, por lo que ni siquiera Passwork puede acceder a sus secretos.
Diseñado para equipos de cualquier tamaño. Passwork escala desde startups pequeñas hasta despliegues empresariales con más de 30.000 usuarios. Está certificado con ISO 27001, probado de forma independiente por HackerOne, y es de confianza de agencias gubernamentales y organizaciones reguladas en toda Europa. El plan estándar comienza en €3/usuario/mes.
Passwork como gestor de secretos
Passwork proporciona las funcionalidades que necesita para la gestión de secretos de infraestructura:
Cifrado de conocimiento cero. Todo el cifrado y descifrado ocurre del lado del cliente — en el navegador, CLI o SDK. El servidor solo almacena datos cifrados. Incluso si alguien compromete el servidor, obtiene blobs cifrados, no secretos.
Diseño API-first. Todo lo que puede hacer en la UI está disponible a través de la API HTTP. Los pipelines CI/CD, los scripts de despliegue y la automatización personalizada utilizan la misma interfaz.
CLI para DevOps. La herramienta passwork-cli gestiona los escenarios más comunes: obtener secretos en variables de entorno antes de ejecutar un comando, recuperar valores individuales para scripts y actualizar credenciales después de la rotación.
Python SDK para automatización compleja. Cuando la CLI no es suficiente — migraciones masivas, verificaciones de integridad, rotación con gestión de errores — el SDK le proporciona acceso programático completo.
Configurando Passwork para infraestructura
1. Cree una bóveda dedicada.
Separe los secretos de infraestructura de las contraseñas de los empleados. Cree una bóveda llamada infrastructure o devops.
2. Organice por entorno y categoría.
infrastructure/
├── production/
│ ├── databases/
│ │ ├── mysql-primary
│ │ └── postgresql-orders
│ ├── cloud/
│ │ └── aws-credentials
│ └── services/
│ ├── stripe-api
│ └── sendgrid-api
├── staging/
│ └── ...
└── development/
└── ...
Esta estructura le permite conceder acceso CI/CD a carpetas específicas. El despliegue de producción obtiene infrastructure/production, staging obtiene infrastructure/staging, los desarrolladores obtienen infrastructure/development.
3. Use campos personalizados para secretos con nombre.
En lugar de poner todo en el campo de contraseña, use campos personalizados con nombres descriptivos:
| Campo | Valor |
|---|---|
MYSQL_HOST | mysql.prod.internal |
MYSQL_USER | backend_svc |
MYSQL_PASSWORD | xK9#mP2$vL7!nQ |
Esto se asigna directamente a las variables de entorno cuando se usa la CLI.
4. Cree cuentas de servicio.
Para la automatización, cree usuarios dedicados en lugar de usar cuentas personales:
| Cuenta | Propósito | Acceso |
|---|---|---|
deploy-prod-svc | Despliegue de producción | solo lectura en infrastructure/production |
deploy-staging-svc | Despliegue de staging | solo lectura en infrastructure/staging |
cred-rotator | Rotación de secretos | lectura-escritura en todos los entornos |
Las cuentas de servicio proporcionan:
- Pista de auditoría clara (ve lo que hizo la automatización vs. lo que hicieron los humanos)
- Independencia del personal (que la gente se vaya no rompe el CI/CD)
- Control de acceso granular (el despliegue de producción no puede modificar secretos)
Usando passwork-cli en CI/CD
Instale via pip:
pip install passwork-python
O use la imagen Docker directamente en los pipelines:
docker run --rm \
-e PASSWORK_HOST="https://passwork.your-company.com" \
-e PASSWORK_TOKEN="$PASSWORK_TOKEN" \
-e PASSWORK_MASTER_KEY="$PASSWORK_MASTER_KEY" \
passwork/passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh
Ejemplo de GitLab CI:
deploy_production:
stage: deploy
image: passwork/passwork-cli:latest
variables:
PASSWORK_HOST: $PASSWORK_HOST
PASSWORK_TOKEN: $PASSWORK_TOKEN
PASSWORK_MASTER_KEY: $PASSWORK_MASTER_KEY
script:
- passwork-cli exec --folder-id "$PROD_SECRETS_FOLDER_ID" ./deploy.sh
environment:
name: production
when: manual
Ejemplo de GitHub Actions:
- name: Deploy with secrets
run: |
docker run --rm \
-e PASSWORK_HOST="${{ secrets.PASSWORK_HOST }}" \
-e PASSWORK_TOKEN="${{ secrets.PASSWORK_TOKEN }}" \
-e PASSWORK_MASTER_KEY="${{ secrets.PASSWORK_MASTER_KEY }}" \
-v ${{ github.workspace }}:/app \
-w /app \
passwork/passwork-cli:latest \
exec --folder-id "${{ vars.SECRETS_FOLDER_ID }}" ./deploy.sh
El modo exec obtiene todos los secretos de la carpeta especificada, los convierte en variables de entorno y ejecuta su comando. Los secretos solo existen durante la duración de ese proceso.
Recuperar secretos en scripts
Para valores únicos en bash:
# Get the database password
DB_PASS=$(passwork-cli get --password-id "<item-id>")
# Get a specific custom field
STRIPE_KEY=$(passwork-cli get --password-id "<item-id>" --field STRIPE_SECRET)
# Get a TOTP code
MFA_CODE=$(passwork-cli get --password-id "<item-id>" --totp)
Docker Compose con secretos
Para entornos de desarrollo local y staging, inyecte secretos a través de exec:
# Start containers with secrets from Passwork
passwork-cli exec --folder-id "<folder-id>" docker compose up -d
En su docker-compose.yml, haga referencia a variables de entorno sin codificar valores:
services:
api:
image: backend:latest
environment:
- MYSQL_HOST=${MYSQL_HOST}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
worker:
image: worker:latest
environment:
- REDIS_URL=${REDIS_URL}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
El modo exec de Passwork establece estas variables antes de iniciar Docker Compose, por lo que los secretos nunca tocan el disco.
Procedimientos de acceso de emergencia
¿Qué ocurre cuando la única persona con acceso de administrador a Passwork está de vacaciones y necesita rotar una credencial comprometida?
Planifique para esto:
1. Múltiples administradores. Al menos dos personas deben tener acceso de administrador a la bóveda de infraestructura. Documente quiénes son.
2. Cuenta de emergencia. Cree una cuenta de administrador de emergencia dedicada con credenciales almacenadas de forma segura fuera de línea (impresas, en una caja fuerte física o con el asesor legal de su empresa). Pruébela trimestralmente.
3. Proceso de recuperación documentado. Escriba exactamente cómo:
- Acceder a la cuenta de emergencia
- Rotar las credenciales comprometidas
- Notificar al equipo lo que sucedió
4. Exportación de respaldo. Exporte periódicamente copias de seguridad cifradas de los secretos críticos. Almacénelas por separado de Passwork con instrucciones claras para el descifrado.
Esto no es paranoia — es continuidad del negocio. Un único punto de fallo en el acceso a secretos puede detener toda su operación.
Auditoría de repositorios en busca de secretos
Antes de migrar a un gestor de secretos, necesita saber qué ya está expuesto.
Herramientas
git-secrets — Herramienta de AWS que evita confirmar secretos y escanea el historial existente:
# Install
brew install git-secrets
# Register common patterns (AWS keys)
git secrets --register-aws
# Scan current repo
git secrets --scan
# Scan commit history
git secrets --scan-history
# Install as pre-commit hook
git secrets --install
truffleHog — escáner profundo que verifica la entropía y los patrones en todas las ramas y el historial:
# Install
pip install trufflehog
# Scan local repository
trufflehog git file://. --only-verified
# Scan with unverified matches too
trufflehog git file://.
gitleaks — rápido y configurable, popular en CI/CD:
# Install
brew install gitleaks
# Scan current state
gitleaks detect --source .
# Scan with verbose output
gitleaks detect --source . --verbose
# Scan as pre-commit
gitleaks protect --source . --staged
Qué hacer con los hallazgos
Inmediato: Si encuentra credenciales activas (claves API actuales, contraseñas de producción), rótelas ahora. No espere hasta haber terminado la auditoría.
Limpiar el historial: Para las credenciales expuestas, reescribir el historial de Git es una opción pero es complejo. Por lo general, es más simple rotar la credencial y dejar el historial como está. Si debe limpiar el historial:
# Use BFG Repo-Cleaner (faster than git filter-branch)
bfg --replace-text secrets.txt repo.git
Prevenir la recurrencia: Instale hooks pre-commit que bloqueen los commits que contienen secretos.
Configuración del hook pre-commit
Usando el framework pre-commit con gitleaks:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Instale:
pip install pre-commit
pre-commit install
Ahora los commits con secretos detectados serán bloqueados.
Rotación de secretos
La rotación no es solo para después de las brechas. La rotación regular limita la ventana de daño si las credenciales se expusieron sin su conocimiento.
Flujo de trabajo de rotación
1. Generate new credential
↓
2. Update target system (database, service)
↓
3. Store new credential in Passwork
↓
4. Verify everything works
↓
5. (Optional) Invalidate old credential
Crítico: Actualice el sistema de destino antes de almacenar en Passwork. De lo contrario, hay una discrepancia — Passwork tiene el nuevo valor mientras el sistema sigue esperando el antiguo.
Rotación con passwork-cli
Rotación de contraseña de PostgreSQL:
#!/bin/bash
set -e
ITEM_ID="<passwork-item-id>"
DB_USER="backend_svc"
# 1. Generate new password
NEW_PASS=$(openssl rand -base64 32)
# 2. Apply to PostgreSQL
psql -h pg.prod.internal -U postgres -c \
"ALTER ROLE ${DB_USER} WITH PASSWORD '${NEW_PASS}';"
# 3. Store in Passwork
passwork-cli update --password-id "${ITEM_ID}" --password "${NEW_PASS}"
echo "Password rotated for ${DB_USER}"
Rotación de contraseña de MySQL:
#!/bin/bash
set -e
ITEM_ID="<passwork-item-id>"
DB_USER="order_service"
NEW_PASS=$(openssl rand -base64 32)
mysql -h mysql.prod.internal -u root -p"${MYSQL_ROOT_PASSWORD}" -e \
"ALTER USER '${DB_USER}'@'%' IDENTIFIED BY '${NEW_PASS}';"
passwork-cli update --password-id "${ITEM_ID}" --password "${NEW_PASS}"
echo "Password rotated for ${DB_USER}"
Calendario de rotación
| Tipo de secreto | Frecuencia sugerida |
|---|---|
| Contraseñas de bases de datos de producción | 30–90 días |
| Claves API externas | 90 días o según la política del proveedor |
| Tokens de servicio | 7–30 días |
| Claves SSH | 6–12 meses |
Automatice con cron:
# /etc/cron.d/passwork-rotation
# Every Sunday at 3 AM
0 3 * * 0 deploy /opt/scripts/rotate-db-passwords.sh >> /var/log/rotation.log 2>&1
Migración de secretos del código a Passwork
Paso 1: inventario
Liste todos los secretos actualmente en su código base y despliegue:
| Secreto | Ubicación actual | Sistema de destino | Ruta en Passwork |
|---|---|---|---|
| Contraseña MySQL prod | .env.production | mysql.prod | infrastructure/production/databases/mysql-primary |
| Clave API de Stripe | config/secrets.yml | Stripe API | infrastructure/production/services/stripe-api |
| Clave de acceso de AWS | Variables CI/CD | AWS | infrastructure/production/cloud/aws-credentials |
Paso 2: crear estructura en Passwork
Configure carpetas que coincidan con su estructura de entorno/categoría. Cree registros con nombres descriptivos y campos personalizados apropiados.
Paso 3: actualizar las aplicaciones
Reemplace los valores codificados en duro con búsquedas de variables de entorno:
# Before
stripe.api_key = "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
# After
import os
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
Esto sigue el principio de la aplicación 12-factor: almacene la configuración en el entorno. Su aplicación debe:
1. Nunca contener secretos en el código. Ni en archivos fuente, ni en archivos de configuración que se confirman.
2. Leer secretos de las variables de entorno. Esta es la interfaz estándar que funciona en todas partes — contenedores, VMs, serverless, desarrollo local.
3. Fallar rápido si faltan secretos. No use silenciosamente los valores por defecto. Si DATABASE_URL no está configurada, falle inmediatamente con un error claro:
import os
import sys
required_vars = ["DATABASE_URL", "STRIPE_SECRET_KEY", "JWT_SECRET"]
missing = [var for var in required_vars if not os.environ.get(var)]
if missing:
print(f"Missing required environment variables: {', '.join(missing)}")
sys.exit(1)
4. Nunca registrar ni exponer secretos. No en mensajes de error, no en salidas de depuración, no en trazas de pila.
Este enfoque funciona independientemente de dónde vengan los secretos — Passwork, otra bóveda o variables CI/CD. Su aplicación no se preocupa por la fuente; solo lee variables de entorno.
Paso 4: actualizar CI/CD
Modifique los pipelines para obtener secretos de Passwork antes del despliegue:
# Before
script:
- export STRIPE_KEY=$STRIPE_KEY_CICD_VAR
- ./deploy.sh
# After
script:
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh
Paso 5: limpieza
- Elimine los secretos de las variables CI/CD (conserve solo las credenciales de conexión de Passwork)
- Elimine los archivos
.envcon credenciales de producción - Elimine los secretos de los archivos de configuración
- Ejecute escáneres de secretos para verificar que no queda nada
Importación de archivos .env a través del Python SDK
Para migración masiva:
import os
from pathlib import Path
from passwork import Client
def migrate_env_file(env_path: str, folder_id: str, tags: list):
"""Import secrets from a .env file into Passwork."""
client = Client(
url=os.environ["PASSWORK_HOST"],
token=os.environ["PASSWORK_TOKEN"],
)
env_file = Path(env_path)
secrets_dict = {}
for line in env_file.read_text().splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
secrets_dict[key.strip()] = value.strip().strip('"\'')
client.create_password(
folder_id=folder_id,
title=env_file.stem,
fields=secrets_dict,
tags=tags,
)
print(f"Imported {len(secrets_dict)} secrets from {env_path}")
# Usage
migrate_env_file(
env_path="./legacy/.env.production",
folder_id="<infrastructure-production-folder-id>",
tags=["production", "imported"],
)
Taller: auditar y migrar
Reserve 2–3 horas para este ejercicio.
Parte 1: escaneo de secretos (30 minutos)
- Instale un escáner:
pip install trufflehog
# or
brew install gitleaks
- Escanee sus repositorios principales:
trufflehog git file://./your-repo --only-verified
# or
gitleaks detect --source ./your-repo --verbose
- Documente los hallazgos:
| Repositorio | Archivo/Commit | Tipo de secreto | Estado |
|---|---|---|---|
| backend | .env.prod (eliminado en abc123) | Contraseña BD | Necesita rotación |
| frontend | config.js línea 42 | Clave API (prueba) | Falso positivo |
- Rote inmediatamente las credenciales de producción activas.
Entregable: Informe de escaneo con estado de remediación
Parte 2: inventario de secretos existentes (30 minutos)
Cree una hoja de cálculo de todos los secretos en su infraestructura:
| Nombre del secreto | Ubicación actual | Entorno | Responsable | Última rotación | Ruta en Passwork (planificada) |
|---|---|---|---|---|---|
| MySQL root | Variables CI/CD | producción | DevOps | Desconocido | infra/prod/databases/mysql-primary |
| Clave Stripe | .env.prod | producción | Backend | Nunca | infra/prod/services/stripe |
| Clave de acceso AWS | Variables CI/CD | todos | DevOps | 6 meses | infra/prod/cloud/aws |
Entregable: Hoja de cálculo de inventario de secretos
Parte 3: configurar Passwork (45 minutos)
- Cree la estructura de carpetas:
infrastructure/
├── production/
│ ├── databases/
│ ├── cloud/
│ └── services/
├── staging/
└── development/
-
Cree cuentas de servicio:
deploy-prod-svc(solo lectura en producción)deploy-staging-svc(solo lectura en staging)cred-rotator(lectura-escritura en todos)
-
Migre 3–5 secretos críticos de su inventario
-
Pruebe la recuperación:
export PASSWORK_HOST="https://passwork.your-company.com"
export PASSWORK_TOKEN="<service-account-token>"
export PASSWORK_MASTER_KEY="<master-key>"
passwork-cli get --password-id "<item-id>"
Entregable: Configuración de Passwork funcional con secretos migrados
Parte 4: actualizar un pipeline CI/CD (30 minutos)
Elija un despliegue no crítico (staging, entorno de desarrollo) y:
- Agregue las credenciales de Passwork a los secretos de CI/CD
- Modifique el pipeline para usar
passwork-cli exec - Pruebe el despliegue
- Elimine los secretos antiguos de las variables CI/CD
Entregable: Pipeline funcional usando Passwork
Parte 5: instalar hooks pre-commit (15 minutos)
pip install pre-commit
# Create .pre-commit-config.yaml
cat > .pre-commit-config.yaml << EOF
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
EOF
pre-commit install
Pruebe intentando confirmar un secreto falso:
echo "aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" > test.txt
git add test.txt
git commit -m "test" # Should be blocked
rm test.txt
Entregable: Hook pre-commit que evita la confirmación de secretos
Parte 6: actualizar .gitignore y documentar el acceso de emergencia (15 minutos)
- Agregue patrones de archivos de secretos a
.gitignore:
cat >> .gitignore << 'EOF'
# Secrets and credentials
.env
.env.*
!.env.example
*.pem
*.key
secrets.yml
credentials.json
EOF
git add .gitignore
git commit -m "Add secret file patterns to .gitignore"
- Cree documentación de acceso de emergencia:
# Emergency Access Procedure
## Break-glass accounts
- Primary: [[email protected]] — has full Passwork admin access
- Secondary: [[email protected]] — has full Passwork admin access
- Emergency: Physical safe in [location], envelope labeled "Passwork Emergency"
## If a secret is compromised
1. Identify the compromised credential
2. Rotate it immediately in the target system
3. Update Passwork with the new value
4. Check audit logs for unauthorized access
5. Notify the team via [channel]
## If Passwork is unreachable
1. Contact [admin1] or [admin2]
2. If unavailable, use break-glass credentials from physical safe
3. Document all actions taken
Entregable: .gitignore actualizado y documento de procedimiento de acceso de emergencia
Artefactos de este capítulo
Al final de este capítulo, debería tener:
- Informe de escaneo de secretos — hallazgos del escaneo del repositorio con estado de remediación
- Inventario de secretos — hoja de cálculo de todos los secretos en su infraestructura
- Estructura de carpetas de Passwork — jerarquía organizada para los secretos de infraestructura
- Cuentas de servicio — cuentas dedicadas para CI/CD y automatización
- Secretos migrados — al menos 5 secretos críticos movidos a Passwork
- Pipeline actualizado — al menos un flujo de trabajo CI/CD usando Passwork
- Hooks pre-commit — gitleaks o git-secrets bloqueando la confirmación de secretos
- .gitignore actualizado — patrones para evitar la confirmación de archivos de secretos
- Procedimiento de acceso de emergencia — proceso de emergencia documentado
Cómo explicarlo al liderazgo
Cuando alguien le pregunte por qué dedica tiempo a la gestión de secretos:
"Estoy moviendo nuestras credenciales — contraseñas de bases de datos, claves API, acceso a la nube — fuera de nuestro código base y hacia un gestor de secretos adecuado. Ahora mismo estas están dispersas por archivos de configuración, variables CI/CD y archivos .env que la gente comparte por Slack. Si el laptop de alguien es robado, o si tenemos un empleado descontento, o si alguien accidentalmente envía un archivo de configuración a un repositorio público, tendríamos un problema serio. Con Passwork, obtenemos almacenamiento centralizado con cifrado, control de acceso para que solo los servicios correctos puedan leer los secretos correctos, y un registro de auditoría de quién accedió a qué. También estoy configurando el escaneo automático para detectar cualquier nuevo secreto antes de que se confirme."
Versión corta: "Estoy asegurando que nuestras contraseñas y claves API no puedan ser robadas si el laptop de alguien desaparece."
Autocomprobación
Higiene del repositorio
- Escaneados todos los repositorios en busca de secretos
- Rotadas las credenciales expuestas
- Hooks pre-commit instalados y funcionando
- .gitignore actualizado con patrones de archivos de secretos
- Sin secretos en el código base actual
Gestión de secretos
- Passwork (o alternativa) configurado
- La estructura de carpetas coincide con los entornos
- Cuentas de servicio creadas para la automatización
- Secretos críticos migrados
- Procedimiento de acceso de emergencia documentado
Integración CI/CD
- Al menos un pipeline usando Passwork
- Solo las credenciales de conexión de Passwork en las variables CI/CD
- Despliegue probado con la nueva configuración
Proceso
- Inventario de secretos documentado
- Calendario de rotación definido
- El equipo sabe que no debe confirmar secretos
- Las aplicaciones leen secretos desde las variables de entorno
Marque al menos 12 de 17 elementos antes de continuar.
Lecturas adicionales
Qué sigue
Secretos fuera del código. Rotación en marcha. Acceso controlado por rol, no por quién conoce el canal de Slack donde alguien pegó la clave hace dos años.
Siguiente: Seguridad del pipeline CI/CD — integración de SAST, DAST y escaneo de dependencias en su flujo de despliegue para que las vulnerabilidades se detecten antes de que se lancen.