Complete "Configuración de pipelines de CI/CD para despliegue continuo" primero para desbloquear esta lección.Ir a la lección anterior

Introducción

Cuando despliegas una aplicación web creada con IA, el código es solo la mitad de la batalla. La otra mitad es todo aquello con lo que el código se comunica: claves de API de inferencia, cadenas de conexión a bases de datos, credenciales de servicios de terceros y feature flags. Manejarlos mal en producción es la causa más común de caídas reales e incidentes de seguridad reales.

Esta lección cubre el flujo de trabajo práctico para mantener los secretos seguros en tres entornos: desarrollo local, staging y producción. Aprenderás un único modelo mental que funciona tanto si despliegas en Vercel, Railway, Render, Fly.io o en un VPS sin más.

Los tres entornos

Toda aplicación que construyas vive al menos en tres lugares, y cada lugar tiene reglas diferentes para los secretos.

El desarrollo local ocurre en tu portátil. Necesitas iterar rápido, así que los secretos viven en un archivo `.env` que está en gitignore. Los cargas con una librería como `dotenv`. Este archivo nunca se commitea y nunca sale de tu máquina.

Staging es una copia de producción con datos falsos. Existe para detectar errores antes de que los usuarios los vean. Los secretos los inyecta el servicio de hosting (Railway Variables, Vercel Environment Variables, etc.) y están limitados a ese entorno.

Producción es a donde llegan los usuarios reales. Los secretos vienen del mismo servicio de hosting pero viven en un namespace más estricto, a menudo con controles de acceso separados. Una clave de staging filtrada es un fastidio; una clave de producción filtrada es un desastre de facturación.

diagrama de 3 entornos dev/staging/prod con diferentes fuentes de secretos

Cargar variables de entorno en el código

El siguiente patrón funciona para casi cualquier backend en Node.js o Python. La idea clave: leer una sola vez al arrancar, fallar de forma ruidosa si falta un secreto requerido.

javascript
import dotenv from 'dotenv';
dotenv.config();
const required = ['DATABASE_URL', 'OPENAI_API_KEY', 'JWT_SECRET'];
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing required env var: ${key}`);
}
}
export const config = {
databaseUrl: process.env.DATABASE_URL,
openaiKey: process.env.OPENAI_API_KEY,
jwtSecret: process.env.JWT_SECRET,
nodeEnv: process.env.NODE_ENV || 'development',
port: Number(process.env.PORT) || 3000,
};

Fíjate en la comprobación al arrancar. Es mucho mejor fallar al iniciar que enviar silenciosamente `undefined` a tu cliente de base de datos a las 3 de la mañana. La llamada a `dotenv` solo lee el archivo si existe, lo que significa que el mismo código se ejecuta sin cambios en producción, donde el host inyecta las variables directamente.

En Python, el equivalente usa `pydantic-settings`:

python
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
openai_api_key: str
jwt_secret: str
node_env: str = "development"
port: int = 3000
settings = Settings()

Pydantic lanzará un error de validación claro si falta cualquier campo requerido, logrando el mismo comportamiento de fallo rápido.

Patrones de conexión a bases de datos

Para una base de datos Postgres en un servicio gestionado como Neon, Supabase o Railway, la cadena de conexión es tu secreto. Trátala como una contraseña.

javascript
import pg from 'pg';
import { config } from './config.js';
export const pool = new pg.Pool({
connectionString: config.databaseUrl,
max: 10,
idleTimeoutMillis: 30000,
ssl: config.nodeEnv === 'production' ? { rejectUnauthorized: true } : false,
});

Aquí importan dos cosas. Primero, el pool de conexiones evita que tu aplicación abra una nueva conexión TCP en cada petición. Segundo, SSL es obligatorio en producción. Muchas bases de datos gestionadas rechazan conexiones sin cifrar, pero ser explícito te protege si cambia el comportamiento por defecto.

Para plataformas serverless (Vercel Functions, Cloudflare Workers), usa un pooler de conexiones que resida fuera de la función — Neon trae uno integrado, Supabase tiene el modo de transacción `pgbouncer`. El objeto pool de arriba vive en la memoria del proceso, lo que en serverless significa un pool nuevo por cada cold start, lo cual es lento y puede agotar las conexiones a la base de datos bajo picos de tráfico.

Gestión de claves de API para servicios de IA

Las APIs de IA (OpenAI, Anthropic, Google, etc.) facturan por token. Una clave filtrada puede vaciar una tarjeta de crédito en horas. Tres reglas te mantienen a salvo.

Primero, establece un límite de gasto estricto en el panel del proveedor. Todos los proveedores importantes ofrecen esto. Segundo, crea claves separadas por entorno — `myapp-dev`, `myapp-staging`, `myapp-prod` — para poder revocar una sin tocar las demás. Tercero, nunca registres la clave en logs ni la incluyas en mensajes de error que se envíen a un servicio de logging.

javascript
const openaiHeaders = {
'Authorization': `Bearer ${config.openaiKey}`,
'Content-Type': 'application/json',
};
async function callOpenAI(messages) {
const res = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: openaiHeaders,
body: JSON.stringify({ model: 'gpt-4o-mini', messages }),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`OpenAI error ${res.status}: ${text}`);
}
return res.json();
}

El handler de errores captura el cuerpo de la respuesta para depuración, lo cual está bien porque no contiene la clave — solo el error del proveedor upstream. Si alguna vez necesitas registrar en logs las cabeceras de la petición para depurar, redacta primero el campo `Authorization`.

Errores comunes y cómo evitarlos

El error más frecuente es commitear un archivo `.env`. Aunque sea una sola vez. El historial de Git es para siempre, y los bots escanean GitHub buscando claves expuestas en cuestión de minutos tras un push. Añade `.env` a `.gitignore` desde el primer día y usa herramientas como `git-secrets` o `gitleaks` en CI para bloquear commits accidentales.

El segundo error es usar la misma base de datos para desarrollo y producción. Parece cómodo hasta que un `DROP TABLE` en un script local borra producción. Usa siempre bases de datos separadas, e idealmente proyectos de proveedor separados, para cada entorno.

El tercer error es rotar claves sin un plan. Cuando rotas la contraseña de una base de datos, cada instancia en ejecución de tu aplicación fallará al reconectarse hasta que se reinicie. En plataformas que lo soporten, usa cadenas de conexión que incluyan la contraseña y diseña tu aplicación para reintentar al arrancar. En plataformas como Vercel, un redespliegue tras rotar el secreto lo resuelve automáticamente.

Resumen

Trata cada secreto como si fuera a filtrarse mañana — porque al final lo hará. Usa archivos `.env` en local con `dotenv` o `pydantic-settings`, deja que tu plataforma de hosting inyecte variables en staging y producción, valida los secretos requeridos al arrancar, usa pool de conexiones a la base de datos con `ssl: true` en producción y asigna a cada clave de API de IA un límite de gasto más una clave única por entorno. Esta configuración lleva una tarde montarla y te ahorra la categoría más común de incidentes en producción.

Práctica de la lección

Punto de control de la lección

Repasa lo aprendido y recibe comentarios sobre tu trabajo.

0/1
Respondidas · 0/1
Gestión de secretos, bases de datos y configuración de entornos