Las plataformas sin servidor aceleran el desarrollo, pero con ellas arrastramos todo un zoológico de plugins: desde envoltorios útiles para el despliegue hasta herramientas para ejecución local, empaquetado de capas y autogeneración de roles. En un día normal ahorran horas, y en uno malo se convierten en una plataforma ideal para atacar la cadena de suministro. A continuación — una explicación de cómo funciona el escenario inyección de plugins serverless, por qué es peligroso, dónde están exactamente los puntos débiles y qué hacer para no encontrarse con «fantasmas» en producción.
¿Qué es la inyección de plugins serverless en términos sencillos?
Los plugins del ecosistema serverless son extensiones que se ejecutan automáticamente durante el proceso de compilación y despliegue. Se registran «ganchos» en etapas como before:package:createDeploymentArtifacts o after:deploy:deploy (la terminología puede variar, la idea es la misma). Si en la cadena entra un plugin malicioso o comprometido, obtiene acceso a variables de entorno, credenciales de CI, configuraciones de funciones y puede modificar sin ser detectado lo que se envía a la nube. El riesgo proviene del hecho de la ejecución automática: los desarrolladores no tienen que invocar explícitamente el código malicioso, se ejecutará «según el horario».
Para entender los mecanismos, conviene tener en mente el modelo de amenazas de la cadena de suministro: desarrollador → gestor de dependencias → plugins/extensiones → infraestructura de compilación → cuenta en la nube. Este bucle lo abordan muchas prácticas de desarrollo seguro, por ejemplo en OWASP SAMM y NIST SSDF, que recomiendan formalizar el control de dependencias y artefactos de compilación.
Dónde se rompe la protección: puntos de entrada habituales
Los proyectos serverless son vulnerables no por magia, sino por la arquitectura de los procesos: mucha automatización, mucha confianza en código externo y permisos amplios en CI. A continuación — los principales puntos donde se «inyectan» plugins.
- Plugins de Serverless Framework — se añaden en
serverless.yml, se obtienen desde npm y se ejecutan vía ganchos. La documentación oficial describe directamente el modelo de extensiones y ganchos, lo que es importante para evaluar riesgos (referencia de plugins). - Lambda Layers/Extensions — las capas y extensiones de AWS pueden contener binarios que interceptan llamadas de red, registros y métricas. Es más fácil «colar» estas piezas mediante el empaquetado automático de capas en un plugin. AWS admite la firma de artefactos de funciones y capas mediante AWS Signer; conviene activarlo como higiene básica (AWS Lambda Code Signing).
- Azure Functions Extensions/NuGet — las extensiones se descargan vía
extensions.csprojy feeds de NuGet; la sustitución del feed o de dependencias permite introducir scripts post-build (documentación sobre extensiones). - Dependencias de GCP Cloud Functions/Run — npm/pip/poetry/gradle, donde los riesgos de la cadena de suministro son análogos, y los scripts de CI a menudo ejecutan pasos arbitrarios antes/después de la compilación (dependencias GCF).
- Herramientas de ejecución local — plugins «offline»/«emulator» que tienen acceso a .env y secretos para depuración local; la infección aquí a menudo se transmite al CI mediante caché y archivos lock.
Cómo se ve un ataque de principio a fin
Analizaremos un escenario verosímil que aparece en distintas variantes en equipos reales.
- Sustitución de dependencias del plugin. El atacante publica un paquete homónimo con un error tipográfico (typosquatting) o compromete la cuenta del autor. Sale una nueva versión «minor» para que se actualice automáticamente en el CI.
- Ejecución automática en el gancho. El malicioso añade un gancho
before:deploy:deploye inserta sin llamar la atención una Lambda Layer adicional, cambia variables de entorno, activa un proxy de red o descarga secretos (AWS_ACCESS_KEY_ID, SLACK_WEBHOOK, etc.). - Persistencia. El plugin crea un recurso invisible (por ejemplo, una role/política IAM independiente o una función retransmisora «temporal») para sobrevivir a una reversión de versión.
- Exfiltración y movimiento lateral. A través de la extensión/capa se proxifica el tráfico, se recopilan tokens de servicios y metadatos, y luego el atacante se mueve hacia cuentas vecinas, buckets y colas.
Desde fuera se ve un despliegue «verde». Por dentro — artefactos modificados y telemetría silenciosa hacia afuera. Por eso en proyectos sin servidor es importante no solo probar el código de las funciones, sino controlar el «meta-código»: plugins, plantillas, capas y pasos de CI.
Signos de compromiso: dónde mirar primero
Buena noticia: muchas trazas se pueden notar si sabes dónde buscar. A continuación — lista de indicadores y áreas de revisión.
- Desviación en IaC/configuración: en
serverless.ymlaparecen nuevos plugins o configuraciones «opcionales» que no estaban en el MR/PR. - Layers/Extensions inesperadas: las funciones muestran capas adicionales, cambiaron los manejadores, aparecen extensiones de «observabilidad» externas sin tickets.
- Anomalías de red: funciones Lambda que antes no tenían tráfico saliente a Internet (VPC egress=0) de repente «tocan» dominios no relacionados con el backend.
- Deriva de permisos: las roles IAM de funciones ganan nuevos permisos como
iam:PassRole,lambda:UpdateFunctionCodeo accesos a KMS que no fueron aprobados. - Logs de CI: en los registros de build y despliegue aparecen pasos/scripts adicionales («postinstall», «prepare», «prepack») que no están en el repositorio.
Práctica: ejemplo demostrativo de un plugin «astuto»
Para entender la mecánica, basta ver un ejemplo simplificado. Supongamos que tenemos un proyecto con Serverless Framework con un fragmento de configuración así:
plugins:
- serverless-offline
- serverless-layer-packer
- serverless-my-helper # parece insignificante
Dentro de serverless-my-helper el desarrollador (o el atacante) registra un gancho:
// index.js del plugin
class MyHelper {
hooks = {
'before:deploy:deploy': this.injectLayer.bind(this)
};
async injectLayer() {
const env = process.env;
// acceso a tokens, variables de entorno de CI, etc. // modificación de serverless.service.provider.layers, añadidos en env
}
}
module.exports = MyHelper;
Si este paquete viene de un registro externo sin versiones fijadas y sin auditoría, obtendrás «código no contabilizado» que se ejecutará en el núcleo del ciclo de despliegue. Eso es exactamente a lo que apunta la inyección de plugins serverless.
Prevención: mínimo técnico básico
No hay una bala de plata, pero sí un conjunto de prácticas que reducen drásticamente la probabilidad y el impacto de un ataque. Empezamos por lo obvio, pero obligatorio.
- Versiones estrictas y archivos lock. Activa «fail-on-update» ante la deriva de
package-lock.json/pnpm-lock.yaml, usa rangos de versión permitidos solo vía revisión de código. - Registros proxy privados. Proxifica npm/pip/nuget mediante un caché privado (Verdaccio, Nexus, Artifactory) con una lista blanca para plugins y bloqueo automático de paquetes «desconocidos».
- Firma y verificación de artefactos. Para funciones/capas activa la firma (AWS Signer para Lambda) y la verificación en el despliegue; para contenedores y ZIP usa Sigstore/cosign.
- Origen de builds (SLSA). Define un nivel objetivo mínimo de SLSA y guarda el provenance; no es burocracia, es una forma de rastrear rápidamente de dónde viene un artefacto.
- SBOM y política de dependencias. Genera SBOM (CycloneDX, SPDX), guárdala junto al artefacto, y bloquea el despliegue si aparecen nombres de paquetes inesperados.
- CI impecable. Prohíbe egress de red en pasos que no lo necesitan; usa runners efímeros; evita
npm install --no-frozen-lockfileen pipelines de producción. - Permisos mínimos en roles. Las roles IAM de las funciones no necesitan permisos para gestionar las propias funciones. Separa la «role de ejecución» de la «role de despliegue».
- Aislamiento del tráfico saliente en tiempo de ejecución. Para AWS Lambda — aislamiento VPC y egress a través de NAT/proxy controlado; para Cloud Functions/Run — Cloud NAT/Serverless VPC Access con políticas de egress.
Políticas y procesos: cómo no ahogarse en excepciones
La tecnología solo funciona con procesos que la respalden. A continuación — un conjunto de reglas sencillas que ayudarán al equipo a no discutir cada cambio desde cero.
- Registro de plugins aprobados. Mantén una lista de «plugins aprobados» con versión, responsable y justificación. Cualquier nombre nuevo solo se acepta mediante ticket y revisión.
- Pasaporte regular de funciones. Cada dos semanas genera un informe: «qué capas/extensiones/variables tiene cada función» y haz que lo firme el responsable.
- Regla «un cambio — un MR». La actualización de un plugin no debe ir junto con lógica de negocio. Así es más fácil revertir y analizar el riesgo.
- Bloqueo de producción por ventana horaria. Despliegues en horario laboral y solo con la disponibilidad de la cadena de guardia completa (Dev, Sec, Ops), para no tomar decisiones críticas solo por la noche.
Plan rápido de implementación de controles (paso a paso)
Si quieres empezar «el lunes», sigue esta ruta — es realista para un proyecto típico.
- Semana 1: activar «frozen lockfile» en todos los pipelines de producción; configurar un registro proxy privado; recopilar la lista de plugins y capas actuales.
- Semana 2: añadir generación de SBOM (CycloneDX para npm/poetry/maven) y una regla simple: si la SBOM cambia, el despliegue requiere confirmación manual.
- Semana 3: habilitar la firma de artefactos (AWS Signer o cosign para contenedores/ZIP) y la validación en el momento del despliegue.
- Semana 4: recortar el egress en CI y en funciones que no lo necesiten; implantar un informe sobre capas/extensiones modificadas.
- Semana 5+: implementar la política de «plugins aprobados», realizar ejercicios tabletop: cómo reacciona el equipo ante la comprometición de un plugin.
Herramientas y servicios que realmente ayudan
La elección depende del stack, pero conviene mencionar algunas direcciones útiles.
- Gestión de dependencias: proxy npm privado (Verdaccio/Nexus/Artifactory), política de «solo scopes aprobados».
- Análisis de SBOM: CycloneDX CLI, Syft/Grype, Dependency-Track — comprobación automática de deriva y vulnerabilidades.
- Firma y provenance: Sigstore/cosign, in-toto, y enforcement de políticas en CI y en la etapa de despliegue.
- Actualizaciones automáticas bajo control: Renovate/Dependabot con reglas «no auto-merge para plugins», informes y batching de parches.
- Control en tiempo de ejecución: control de egress (NAT + ACL de egress), registro de DNS, alertas por dominios «nuevos» desde funciones.
Cómo comprobarse: mini lista de verificación
Si hay poco tiempo, repasa esta lista — ayuda a entender rápidamente cuánto te falta para un modelo maduro de gestión de plugins.
- Archivos lock obligatorios; la compilación falla si no coinciden.
- Plugins/capas solo desde el proxy privado.
- Existe una lista de «plugins aprobados» y un proceso para añadir nuevos.
- Cada despliegue va acompañado de SBOM y firma del artefacto.
- CI no tiene tráfico saliente sin necesidad explícita.
- Funciones sin necesidad de Internet — sin egress a Internet.
- Se dispara una alerta al aparecer una capa/extensión nueva en una función.
FAQ: brevemente sobre objeciones típicas
«Pero tenemos un ciclo de lanzamientos rápido, no podemos frenar el despliegue por cada actualización de plugin».
Respuesta: agrupa actualizaciones, reserva dos ventanas semanales para la «entrega de paquetes», usa un proyecto canario para probar actualizaciones de plugins antes de llevarlas a producción.
«La firma de artefactos es demasiado compleja».
Respuesta: empieza con un esquema mínimo — firma solo los artefactos de producción y valida en el despliegue. AWS Lambda soporta verificación de firmas integrada (documentación).
«Un plugin malicioso aún podrá comunicarse hacia fuera».
Respuesta: no podrá si el CI no tiene egress y las funciones están en subredes privadas con NAT y ACL de egress gestionados. Mantén la red «cerrada por defecto».
Conclusiones
La inyección de plugins serverless no es una excentricidad: es un efecto lógico de nuestra preferencia por la automatización. La buena noticia es que la protección cabe en pasos comprensibles: registra el origen de los artefactos, limita las fuentes de dependencias, corta el tráfico saliente donde no se necesita y trata los plugins como código con el mismo nivel de desconfianza que cualquier componente externo. Así los plugins volverán a ser lo que deben ser — aceleradores, no «puertas secretas» a producción.