Cómo almacenar claves de API de forma segura en 2026

Sun Aug 30 2026

Cómo almacenar claves de API de forma segura en 2026

Pero las variables de entorno son solo una base para la configuración de bajo impacto; producción necesita una estrategia completa de secretos. Todo lo que se envía al código del navegador es público, independientemente de la minificación u ofuscación.

Por eso, almacena cada valor según el daño que causaría una filtración. Haz que esa elección pueda ejecutarse desde el desarrollo local hasta la revocación. Identificaremos las vías habituales de filtración y elegiremos un nivel de almacenamiento. Después, obtendremos los secretos en tiempo de ejecución, estableceremos una política de rotación basada en el riesgo y cubriremos Git, CI/CD, navegadores y asistentes de programación con IA.

Tu clave es una credencial, no una cadena inofensiva

Pero los consejos habituales se detienen en .env y .gitignore. Eso gestiona la higiene del repositorio, pero ignora el acceso en tiempo de ejecución, los registros de CI y la revocación.

Por eso, clasifica un valor según lo que una persona no autorizada podría hacer con él. Una credencial filtrada puede abrir una base de datos o autorizar pagos. Puede exponer datos privados, modificar la infraestructura o firmar tokens, según sus permisos. Un identificador público de analítica tiene un perfil de riesgo distinto al de una credencial de cloud con acceso administrativo.

Y el resumen disponible del informe State of API Security 2026 de 42Crunch afirma que la ausencia de autenticación fue la vulnerabilidad de API informada con mayor frecuencia en 2025. También señala una autorización defectuosa a nivel de objeto y de función, junto con la falacia del cliente confiable: el comportamiento del frontend no puede imponer la autorización.

El almacenamiento de secretos no solucionará la ausencia de una comprobación de autorización. Pero puede dificultar que un atacante obtenga la credencial.

La mayoría de las filtraciones son errores operativos habituales

La mayoría de los incidentes relacionados con secretos son aburridos. Por eso, una política de almacenamiento debe sobrevivir a las tareas habituales de depuración, despliegue y colaboración.

La exposición en el control de código fuente conserva copias a lo largo del tiempo. La exposición en tiempo de ejecución revela los valores cargados por un proceso, contenedor, pod o pipeline. Por tanto, defiende ambas vías por separado.

UbicaciónCómo se filtraPráctica más segura
Repositorio de GitUna clave está codificada directamente o se confirma un archivo .env; los clones, forks, cachés y copias de seguridad pueden conservarlaIgnora los archivos de secretos locales. Escanea el historial. Activa la respuesta ante incidentes
Contenedor en ejecucióndocker exec <ctr> env imprime el entorno del proceso a alguien con suficiente accesoRestringe el acceso en tiempo de ejecución y solicita solo los valores necesarios
Pod de Kuberneteskubectl exec <pod> -- env vuelca las variables de entorno a un operador con acceso al shellUsa la identidad de carga de trabajo e inyección controlada o recuperación en tiempo de ejecución
Trabajo de CI/CDecho $SECRET_KEY o printenv envía los valores a los registros y artefactosEnmascara los valores y restringe los permisos del pipeline. Aísla las credenciales de producción
Chat o unidad compartidaLos desarrolladores envían archivos .env para desbloquear un despliegueProporciona a cada persona acceso mediante un servicio de secretos auditable
DepuraciónLos objetos de configuración, datos de solicitudes o cadenas de conexión entran en los registros y excepcionesRedacta los diagnósticos. Excluye los secretos de los mensajes de error

Las variables de entorno mantienen los valores fuera del código fuente y permiten distintas configuraciones por entorno. También viven en la memoria del proceso y pueden ser leídas por usuarios o procesos con suficientes privilegios. Úsalas como límite del repositorio y añade una protección más sólida cuando el impacto lo justifique.

.env es el nivel básico; un gestor de secretos es el nivel superior

Considera esta escala como una adecuación creciente para el uso por parte de aplicaciones, en lugar de una clasificación universal de madurez:

  1. Código fuente codificado directamente: la peor opción. El valor entra en el control de versiones, cuyo propósito es recordar los cambios.
  2. Variables de entorno: una base útil. Separan los valores del código de la aplicación y permiten configuraciones por entorno.
  3. Gestores de secretos: la opción de producción para credenciales de alto impacto. Añaden almacenamiento cifrado, políticas de acceso, caducidad, flujos de trabajo de rotación y revisión del acceso.
  4. Notas cifradas del lado del cliente: solo para referencia personal. Una aplicación de notas puede ayudar a una persona a recordar una credencial; un servidor nunca debe depender de que un ingeniero la copie en producción.

Como indica FloopFloop, “Las variables de entorno son el nivel básico; un gestor de secretos adecuado es el nivel superior”. La frase es memorable porque la distinción importa.

Un gestor añade SDK o agentes, políticas de identidad, cambios en el despliegue, gestión de fallos y responsabilidad operativa. Para un prototipo local sin credenciales de producción ni despliegue compartido, eso puede ser una formalidad innecesaria. Usa un archivo local ignorado y vuelve a evaluar la decisión antes de producción.

En las máquinas locales, mantén .env legible únicamente por el usuario de la aplicación y nunca lo uses como mecanismo de distribución de credenciales del equipo.

Usa una pregunta para decidir dónde pertenece un valor

Pregunta:

Si este valor se filtrara, ¿alguien podría obtener acceso o causar daños?

Un sí lo convierte en un secreto; en producción, almacénalo en un gestor o en un sistema controlado equivalente de inyección de secretos. Un no lo convierte en configuración ordinaria. “Público” significa intencionadamente público y restringido por diseño, y solo cuando el proveedor pretende esa exposición.

Configuración ordinariaSecreto de producción
APP_ENV y LOG_LEVELContraseñas de bases de datos y URL de bases de datos que contengan credenciales o concedan acceso de conexión
Indicadores de funcionalidades, puertos y rutas del sistema de archivosClaves secretas de Stripe y tokens de GitHub
Nombres de host y URL baseSecretos de webhook
ID de cliente públicos de OAuth destinados al uso en el navegadorClaves de firma JWT
Identificadores de analítica diseñados para uso por parte del clienteClaves privadas TLS, claves IAM y credenciales de cuentas de servicio

Una credencial de Stripe del backend sigue siendo sensible porque su proveedor la denomina API key. Un identificador de analítica visible en el navegador puede ser público porque sus permisos y cuota se diseñaron para esa exposición.

Considera una pequeña aplicación Node.js que procesa webhooks de Stripe y almacena pedidos en PostgreSQL. APP_ENV y LOG_LEVEL describen el comportamiento en tiempo de ejecución. STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET y DATABASE_URL pueden autorizar acciones o exponer datos. Colócalos en niveles separados.

Obtén los secretos en tiempo de ejecución, no mediante copiar y pegar

Entre proveedores y lenguajes, autentica la carga de trabajo, solicita valores con nombre, valídalos al inicio y mantenlos fuera de los registros. La implementación cambia según la plataforma; el límite no.

Node.js

El siguiente pseudocódigo neutral respecto al proveedor muestra el límite; no es un ejemplo ejecutable de un SDK. Sustituye secretManager.getMany por el cliente y la configuración de identidad de carga de trabajo del proveedor seleccionado.

// Pseudocode: replace with your provider's SDK.
const config = await secretManager.getMany([
  "STRIPE_SECRET_KEY",
  "STRIPE_WEBHOOK_SECRET",
  "DATABASE_URL",
]);

for (const name of [
  "STRIPE_SECRET_KEY",
  "STRIPE_WEBHOOK_SECRET",
  "DATABASE_URL",
]) {
  if (!config[name]) {
    throw new Error(`Required secret is unavailable: ${name}`);
  }
}

const stripe = createStripeClient(config.STRIPE_SECRET_KEY);
const database = createDatabase(config.DATABASE_URL);

// Pass only the credential or client each component needs.
// Never log config or include secret values in errors.

Este es el momento en que el servicio de pedidos recibe los tres valores sensibles; APP_ENV y LOG_LEVEL siguen siendo configuración ordinaria del despliegue. (Consulta la guía de seguridad de API en Node.js.)

Python

Para Azure, Microsoft documenta DefaultAzureCredential con SecretClient de azure-identity y azure-keyvault-secrets. El vault_url omitido debe proceder de una configuración de despliegue no secreta.

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_url, credential=credential)

stripe_secret_key = client.get_secret("StripeSecretKey").value
stripe_webhook_secret = client.get_secret("StripeWebhookSecret").value
database_url = client.get_secret("DatabaseUrl").value

if not all((stripe_secret_key, stripe_webhook_secret, database_url)):
    raise RuntimeError("Required secrets are unavailable")

Trata los fallos de recuperación como un fallo de despliegue o de inicio. Registra las excepciones del proveedor únicamente mediante un canal de errores redactado y con acceso controlado.

Go

Aquí también, manager.Get y OpenDatabase son marcadores de posición para el SDK de tu proveedor y el paquete de base de datos.

// Pseudocode: replace manager.Get and OpenDatabase with real clients.
secrets, err := manager.Get(ctx, []string{
	"STRIPE_SECRET_KEY",
	"STRIPE_WEBHOOK_SECRET",
	"DATABASE_URL",
})
if err != nil {
	return fmt.Errorf("load required secrets: %w", err)
}

for _, name := range []string{
	"STRIPE_SECRET_KEY",
	"STRIPE_WEBHOOK_SECRET",
	"DATABASE_URL",
} {
	if secrets[name] == "" {
		return fmt.Errorf("required secret %s is unavailable", name)
	}
}

db, err := OpenDatabase(secrets["DATABASE_URL"])
if err != nil {
	return fmt.Errorf("open database: %w", err)
}

Pasa un cliente o identificador de credencial con un alcance limitado en lugar del mapa de configuración completo. Eso limita el acceso accidental dentro del proceso.

Elige el gestor que tu infraestructura pueda hacer cumplir

No compres un gestor de secretos porque una tabla comparativa lo llame “el mejor”. Elige en este orden:

  1. Empieza por el servicio nativo de tu cloud cuando tus cargas de trabajo ya utilicen la identidad y la supervisión de ese cloud.
  2. Adáptate al modelo de despliegue: una infraestructura híbrida puede justificar Vault; los equipos centrados en desarrolladores pueden preferir un flujo de distribución más sencillo.
  3. Comprueba la capacidad operativa: un servicio potente que nadie pueda actualizar, supervisar o recuperar es una responsabilidad.

La comparativa de CiphersSecurity describe usos generales:

  • HashiCorp Vault: entornos híbridos complejos que necesitan secretos dinámicos y un equipo preparado para operar Vault.
  • AWS Secrets Manager: equipos estandarizados en AWS que utilizan controles nativos de identidad y despliegue.
  • Azure Key Vault: cargas de trabajo de Azure que utilizan identidades de Microsoft Entra y supervisión de Azure.
  • Doppler o Infisical: flujos de trabajo centrados en desarrolladores que necesitan una distribución sencilla entre entornos.
  • Akeyless: organizaciones que evalúan un modelo sin vault y de conocimiento cero.

Úsalos como descripciones de adecuación, no como clasificaciones. Como mínimo, exige almacenamiento cifrado, identidad de carga de trabajo, lecturas con privilegio mínimo y acceso auditable. Exige compatibilidad con caducidad o rotación y una integración con CI/CD que mantenga los valores fuera de la salida. El registro de recuperación varía según el servicio y la integración, así que verifica qué registra la ruta elegida.

Ninguna opción cuesta menos para toda arquitectura; mide el tiempo de configuración, la respuesta ante incidentes y la fricción de los desarrolladores en tu propio entorno.

Azure Key Vault demuestra el patrón de control

El ejemplo de Microsoft Learn crea un vault con autorización RBAC y protección contra purgas:

az keyvault create --name "<vault-name>" \
  --resource-group "myResourceGroup" \
  --enable-rbac-authorization true \
  --enable-purge-protection true

Añade un secreto con el ejemplo documentado de caducidad a 180 días:

az keyvault secret set \
  --vault-name "<vault-name>" \
  --name "MyApiKey" \
  --value "<secret-value>" \
  --expires "$(date -u -d '+180 days' +'%Y-%m-%dT%H:%M:%SZ')"

Esa sintaxis de date es para GNU/Linux. Los usuarios de macOS deben adaptar el comando de marca de tiempo. Sustituye el nombre del vault, la suscripción, la identidad, la región y las políticas de la organización antes de ejecutar cualquier comando.

Una configuración práctica asigna después a la aplicación el rol Key Vault Secrets User en lugar de un acceso administrativo amplio. Considera vaults separados por entorno o aplicación cuando el aislamiento y la administración lo justifiquen.

Configura las piezas restantes como un procedimiento:

  1. Suscríbete a los eventos SecretNearExpiry mediante Event Grid.
  2. Envía los registros de diagnóstico AuditEvent a Log Analytics.
  3. Crea alertas sobre operaciones SecretGet no autorizadas.
  4. Restringe el acceso de red con Private Link o reglas de firewall.
  5. Usa los endpoints HTTPS del servicio para todas las comunicaciones.

Los nombres específicos del proveedor cambian, pero el patrón de control se generaliza: identidad de carga de trabajo, permisos limitados, caducidad, alertas, restricción de red y registros de acceso.

La rotación es un calendario basado en el riesgo, no un número mágico

Un recordatorio del calendario que diga “rotar clave” sirve de poco si nadie puede revocar el valor antiguo, verificar el reemplazo o saber quién accedió a él.

Esta es la política inicial recomendada por Blackhawk, no un estándar universal:

  • Credenciales de alto impacto o expuestas con frecuencia: rótalas diariamente o por despliegue cuando sea práctico y prefiere credenciales de corta duración o dinámicas.
  • Claves de API humanas o de producción de larga duración: rótalas cada 30–90 días, sujetas a los límites del proveedor y al riesgo operativo.
  • Certificados: supervisa su caducidad y revísalos mensualmente; renuévalos según la duración de su certificado.
  • Claves de firma y claves privadas: define un plan de cambio específico para la clave, incluido dónde pueden coexistir las versiones antigua y nueva.
  • Credenciales de servicio de menor riesgo: usa hasta 180 días como punto de partida, con periodos más cortos cuando el impacto sea mayor.

Microsoft utiliza 180 días en su ejemplo de Azure y documenta notificaciones de proximidad de caducidad. Infisical describe los secretos dinámicos como credenciales generadas bajo demanda con caducidad automática, lo que reduce el intervalo entre la emisión y la revocación.

Si el proveedor no admite la coexistencia o la reversión automatizada, no fuerces una rotación diaria. Reduce los permisos, acorta la duración del token cuando sea posible y documenta el límite real del proveedor. Que la rotación diaria sea segura depende del tiempo de reversión, la compatibilidad con la coexistencia y el uso de las credenciales. Son hechos del despliegue, no una política universal.

Usa un cambio de dos claves cuando el proveedor lo admita:

  1. Emite el reemplazo.
  2. Almacena y despliega la nueva versión.
  3. Verifica el tráfico y el estado de la aplicación.
  4. Revoca o desactiva la credencial antigua.
  5. Comprueba en los registros si continúa utilizándose el valor antiguo.

Para la aplicación de Stripe y PostgreSQL, mantén la clave antigua de Stripe aceptada mientras se verifica el nuevo despliegue y después revócala. Para PostgreSQL, crea un rol de reemplazo cuando la base de datos y la configuración del despliegue permitan credenciales superpuestas. De lo contrario, usa una ventana de mantenimiento o un rol separado, confirma las escrituras y desactiva la credencial antigua.

Un navegador no puede ocultar una clave a su usuario

Si un secreto llega a JavaScript del navegador, mapas de origen, solicitudes de red o un binario móvil, asume que el usuario puede obtenerlo. Un paso de compilación no cambia eso.

Si un proveedor denomina API key a un valor enviado al navegador, trata los permisos, no la etiqueta, como el límite de seguridad.

Usa este flujo:

  1. El navegador se autentica en tu aplicación.
  2. Tu backend autoriza la operación solicitada.
  3. Tu backend llama a la API de terceros con su secreto del lado del servidor.
  4. Tu backend devuelve únicamente los datos permitidos.

Cuando un proveedor requiera una clave visible en el navegador, utiliza una clave deliberadamente pública restringida por dominio, origen, operación, cuota y otros mecanismos disponibles. Una credencial de servidor privilegiada pertenece al servidor.

Los asistentes de IA dificultan el cumplimiento de la gestión de secretos

Los asistentes de programación añaden lugares donde los desarrolladores pueden pegar o generar un secreto: prompts, ventanas de contexto, modificaciones de configuración, parches generados, fixtures y transcripciones de chat.

Mantén los secretos fuera de los prompts y fixtures de prueba. Usa marcadores de posición y credenciales de prueba inyectadas. Revisa la configuración y los parches generados para detectar credenciales codificadas directamente antes de que entren en el repositorio.

Añade análisis del repositorio y del pipeline con TruffleHog, Gitleaks o GitHub Secret Scanning. El análisis detecta errores; los permisos de la carga de trabajo limitan lo que esos errores pueden exponer.

Mueve los secretos existentes en cuatro fases

Rama de emergencia: si una credencial está expuesta ahora, revócala inmediatamente cuando el proveedor admita la revocación. De lo contrario, rótala y desactiva la versión expuesta. La limpieza del repositorio viene después.

Migración normal: audita primero y después mueve los valores de mayor impacto.

1. Audita cada copia

Busca en el código fuente, el historial de Git, los archivos .env, los Dockerfiles y la configuración de CI/CD. Comprueba también los artefactos de compilación, los registros y los documentos compartidos. Ejecuta TruffleHog, Gitleaks o GitHub Secret Scanning y revisa manualmente los hallazgos.

2. Mueve primero los secretos críticos

Crea credenciales de reemplazo cuando sea posible. Colócalas en el gestor seleccionado, concede a la aplicación una identidad limitada y cambia la aplicación para que recupere los valores en tiempo de ejecución.

3. Limpia el texto sin formato

Elimina los valores de los archivos actuales, registros, fixtures y salidas del pipeline. Borrar la línea es mantenimiento. Revocar la credencial es respuesta ante incidentes.

Reescribir el historial puede reducir el redescubrimiento, pero no sustituye a la revocación. Asume que cualquiera que haya clonado el repositorio aún puede poseer el valor antiguo.

4. Comunica y perfecciona

Documenta el propietario, el propósito y los lectores autorizados. Registra el procedimiento de caducidad y rotación, la vía de revocación de emergencia y el flujo de desarrollo local. Si los desarrolladores todavía intercambian archivos .env en el chat, corrige el flujo de trabajo en lugar de documentar el hábito.

La lista de comprobación del almacenamiento seguro pertenece al pull request

Úsala como instrumento de revisión:

  • ¿Puede el revisor identificar la ubicación de almacenamiento?
  • ¿La carga de trabajo utiliza una identidad administrada, OIDC o un mecanismo equivalente?
  • ¿Están explícitos los nombres de los secretos permitidos y sus lectores?
  • ¿Se ha designado al responsable de la revocación?
  • ¿Existe una señal de caducidad o rotación?
  • ¿Qué registro de acceso demuestra la recuperación?
  • ¿Están limpios los bundles del navegador, prompts, fixtures, registros, Dockerfiles y el historial de Git?
  • ¿Se ha revocado una credencial expuesta?

Si alguna respuesta es “lo decidiremos más adelante”, mantén la credencial fuera de producción. Esa es la política: usa .env para la configuración de bajo impacto, usa un gestor controlado para los secretos perjudiciales y haz que la revocación forme parte del diseño en lugar de ser una improvisación de emergencia.