Situación anterior
⚠️ Riesgos detectados en CULTIVA IA antes de la migración
- Archivo
.env de producción commiteado accidentalmente en GitHub (enero 2026) — OPENAI_API_KEY y JWT_SECRET expuestos
- Secretos duplicados entre
cultiva-api, cultiva-worker y cultiva-web sin sincronización
- Variables en GitHub Actions como repository secrets dispersos, sin rotación ni auditoría
- Developers con copias locales desactualizadas de
.env que causaron errores en staging
Estructura en Doppler
📂 Árbol de proyectos y configs
📦 cultiva-api (FastAPI + Claude/GPT-4o)
● dev — localhost, sk-test-*, debug
● stg — staging DB, sk-test-*, warn
● prd — prod DB, sk-live-*, sentry
📦 cultiva-worker (Celery + Redis)
● dev — redis local, debug
● prd — redis.prod.cultiva.ai
📦 cultiva-web (Next.js Vercel)
● preview — variables NEXT_PUBLIC_*
● prd — variables NEXT_PUBLIC_* prod
🚀 Migración desde .env — Comandos ejecutados
$ doppler secrets upload .env \
-p cultiva-api -c dev
✓ Uploaded 6 secrets to cultiva-api (dev)
$ doppler secrets -p cultiva-api -c dev
NAME VISIBILITY
DATABASE_URL ••••••••••••••••••
REDIS_URL ••••••••••••••••••
OPENAI_API_KEY ••••••••••••••••••
ANTHROPIC_API_KEY ••••••••••••••••••
JWT_SECRET ••••••••••••••••••
LOG_LEVEL debug
$ echo ".env" >> .gitignore
$ git rm --cached .env
rm '.env'
Secretos — cultiva-api / producción
🔑 Inventario completo — cultiva-api · prd
| Nombre |
Valor (enmascarado) |
Visibilidad |
Tipo |
Entorno anterior |
| DATABASE_URL |
postgresql://db.prod.cultiva.ai:5432/cult•••• |
normal |
string |
.env local |
| REDIS_URL |
redis://redis.prod.cultiva.ai:6379/•••• |
normal |
string |
.env local |
| OPENAI_API_KEY |
sk-live-•••••••••••••••••••••••••••••• |
restricted |
string |
GitHub Secret (expuesto) |
| ANTHROPIC_API_KEY |
sk-ant-live-•••••••••••••••••••••••••• |
restricted |
string |
GitHub Secret |
| JWT_SECRET |
•••••••••••••••••••••••••••••••••••••••••••••••••••••• |
restricted |
string |
.env (commiteado ⚠️) |
| LOG_LEVEL |
warn |
normal |
string |
.env local |
| SENTRY_DSN |
https://••••••@sentry.io/•••• |
normal |
string |
hardcoded en código 😱 |
Configuración de proyectos y ejecución
⚙️ Setup por servicio
$ doppler setup \
--project cultiva-api \
--config dev \
--no-interactive
$ doppler setup \
--project cultiva-worker \
--config dev \
--no-interactive
$ echo "HISTIGNORE='*doppler secrets set*'" >> ~/.zshrc
▶️ Inyección de secretos en ejecución
source .env && uvicorn main:app --reload
$ doppler run -- uvicorn main:app --reload
✓ Injected 7 secrets into process
$ doppler run -p cultiva-worker -- \
celery -A tasks worker
$ doppler run \
--name-transformer camel -- \
node scripts/sync.js
Comandos CRUD de secretos
📝 Gestión individual y bulk
$ doppler secrets set \
OPENAI_API_KEY="sk-live-xxxxxxxxxxxxxxxx" \
--visibility restricted \
-p cultiva-api -c prd
$ doppler secrets get DATABASE_URL --plain \
-p cultiva-api -c prd
postgresql://db.prod.cultiva.ai:5432/cultiva
$ doppler secrets download \
--no-file --format=env \
-p cultiva-api -c dev > .env.backup
$ chmod 600 .env.backup
Tokens de servicio para CI/CD
🤖 Service tokens — GitHub Actions
dp.st.prd.AbCdEf1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxxx
copiar
dp.st.prd.XyZaBc9876543210yyyyyyyyyyyyyyyyyyyyyyyy
copiar
$ doppler configs tokens create github-actions \
-p cultiva-api -c prd \
--max-age 720h --plain
env:
DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN_CULTIVA_API }}
steps:
- run: doppler run -- ./deploy.sh
Integraciones Docker y Kubernetes
⚙️
GitHub Actions
Token de servicio dp.st.prd.* en repository secrets. Doppler inyecta en cada job sin exponer valores.
🐳
Docker Compose
doppler run -- docker compose up pasa secretos como env vars al contenedor sin escribir archivos en disco.
☸️
Kubernetes Secret
kubectl create secret generic app-secrets --from-env-file <(doppler secrets download --format docker)
Onboarding equipo (3 developers)
👩💻 Guía de incorporación — 4 pasos, 2 minutos
PASO 1 — INSTALAR CLI
brew install dopplerhq/cli/doppler
PASO 2 — AUTENTICARSE
doppler login
# abre browser → OAuth con cuenta de empresa
PASO 3 — VINCULAR PROYECTO
cd ~/projects/cultiva-api && doppler setup
# selecciona cultiva-api → dev
PASO 4 — ARRANCAR LA APP
doppler run -- uvicorn main:app --reload
# ✓ sin .env, sin copiar nada, siempre actualizado
Comparativa antes vs. ahora
📊 .env files vs. Doppler centralizado
| Característica |
.env files (antes) |
Doppler (ahora) |
| Secretos en git |
✗ Riesgo real (ocurrió) |
✓ Imposible por diseño |
| Sincronización equipo |
✗ Manual, propenso a errores |
✓ Automática en tiempo real |
| Rotación de secretos |
✗ Actualizar N archivos |
✓ Un cambio, todos los envs |
| Auditoría de accesos |
✗ Ninguna |
✓ Log completo en dashboard |
| CI/CD tokens |
~ GitHub Secrets sin TTL |
✓ Tokens con max-age rotables |
| Onboarding nuevo dev |
✗ Pedir .env manualmente |
✓ doppler login + setup |
| Secretos en Docker/K8s |
~ Archivos en disco |
✓ Inyección en memoria, sin archivos |
Flujo completo de migración
🗂️ Pasos ejecutados — cultiva-api
1
Instalar Doppler CLI y autenticar
brew install + doppler login con cuenta corporativa alvarogimeno2002@gmail.com
$ doppler me
Name: Álvaro Gimeno
Email: alvarogimeno2002@gmail.com
Workplace: CULTIVA IA
2
Subir secretos existentes desde .env
Importación masiva preservando nombres exactos. Sin tocar el código.
$ doppler secrets upload .env.prd \
-p cultiva-api -c prd
✓ Uploaded 7 secrets successfully
3
Marcar secretos sensibles como restricted
OPENAI_API_KEY, ANTHROPIC_API_KEY y JWT_SECRET solo visibles para admins.
$ doppler secrets set \
JWT_SECRET="$(openssl rand -hex 32)" \
--visibility restricted \
-p cultiva-api -c prd
4
Crear tokens de servicio para GitHub Actions
Token con TTL 720h (30 días) para el pipeline de deploy automático.
$ doppler configs tokens create github-deploy \
-p cultiva-api -c prd \
--max-age 720h --plain
5
Limpiar .env del repositorio
Eliminar archivos sensibles del historial de git y añadir al .gitignore.
$ git rm --cached .env .env.prd
$ echo ".env*" >> .gitignore
✓ .env files removed from git tracking