Seguridad en arquitecturas serverless y funciones como servicio
La adopción de serverless y FaaS (Functions as a Service) se ha disparado en los últimos años, impulsada por la promesa de escalabilidad infinita, reducción de costes operativos y agilidad en el desarrollo. Sin embargo, esta arquitectura introduce un nuevo paradigma de seguridad que rompe con los modelos tradicionales basados en perímetros de red, firewalls y sistemas operativos gestionados por el equipo interno. La seguridad ya no es un muro, sino un tejido distribuido que debe gestionarse a nivel de código, identidad, datos y eventos.
En este artículo, exploraremos a fondo la seguridad serverless, con un enfoque práctico en plataformas como AWS Lambda. Abordaremos las amenazas más comunes, las mejores prácticas de hardening y cómo integrar la seguridad en el ciclo de vida de las funciones. No se trata de si tu arquitectura serverless es segura, sino de si has mapeado correctamente la superficie de ataque.
El nuevo modelo de responsabilidad compartida en serverless
En un entorno on-premise, el equipo de operaciones controla el hardware, el hipervisor y el sistema operativo. En IaaS, se comparte la responsabilidad del SO y el middleware. En serverless, la frontera se desplaza: el proveedor (AWS, Azure, GCP) asegura el runtime, la infraestructura subyacente y la ejecución aislada de las funciones. El cliente es responsable de:
- Código de la función: Librerías, dependencias, lógica de negocio.
- Configuración de permisos: Roles IAM, políticas de ejecución.
- Manejo de secretos: Variables de entorno cifradas, servicios como AWS Secrets Manager.
- Validación de entrada: Eventos que activan la función (HTTP, S3, DynamoDB Streams, etc.).
- Gestión de dependencias: Vulnerabilidades en paquetes npm, pip, o NuGet.
[WARNING] Error común: asumir que el proveedor “se encarga de todo”. El proveedor asegura el runtime, pero no tu código ni tus datos. Una función mal escrita puede exponer toda una base de datos.
Principales vectores de ataque en FaaS
Las funciones serverless son efímeras, sin estado y se ejecutan en respuesta a eventos. Esta naturaleza introduce vectores de ataque específicos que no existen en aplicaciones monolíticas.
Inyección de eventos (Event Injection)
Una función se activa mediante un evento (un mensaje de SQS, un objeto subido a S3, una petición HTTP). Si el código confía ciegamente en los datos del evento sin validarlos, un atacante puede inyectar payloads maliciosos.
- Ejemplo: Una función que procesa un archivo JSON de S3 y lo inserta en una base de datos. Si el JSON contiene comandos SQL o de shell, y la función no sanitiza, se produce una inyección.
- Mitigación: Validar y sanitizar TODOS los campos del evento. Usar bibliotecas ORM/ODM con parámetros vinculados. Nunca concatenar datos de eventos directamente en queries o comandos del sistema.
Escalada de privilegios a través de roles IAM
Cada función en AWS Lambda tiene un rol IAM asociado. Un error típico es asignar permisos excesivos (ej: AdministratorAccess o S3:*). Si un atacante logra ejecutar código arbitrario en la función (por ejemplo, mediante una inyección de dependencia), puede usar las credenciales temporales del rol para acceder a recursos no autorizados.
- Principio de mínimo privilegio: El rol de la función debe tener EXACTAMENTE los permisos necesarios. Para una función que solo lee de una tabla de DynamoDB, el rol debe permitir solo
dynamodb:GetItemen esa tabla específica. - Uso de políticas basadas en condiciones: Restringir acciones según etiquetas, IPs de origen o VPC endpoints.
Dependencias envenenadas (Supply Chain Attacks)
Las funciones suelen incluir cientos de dependencias de paquetes públicos (npm, PyPI, Maven). Un paquete malicioso o una versión vulnerable puede comprometer la función.
- Ejemplo real: El ataque
event-streamen npm (2018) que robaba bitcoins. Una función que usara esa dependencia quedaría comprometida. - Mitigación: Escaneo continuo de dependencias con herramientas como Snyk, Dependabot o AWS Inspector. Bloquear versiones específicas en
package-lock.jsonorequirements.txt. Considerar el uso de un repositorio privado de paquetes (como AWS CodeArtifact).
Denegación de servicio financiera (Financial DoS)
A diferencia de un servidor tradicional, donde el coste es fijo, en serverless pagas por ejecución y duración. Un atacante puede enviar un aluvión de eventos que disparen la función miles de veces por segundo, generando una factura astronómica.
- Mitigación: Configurar concurrencia reservada en AWS Lambda para limitar el número de ejecuciones simultáneas. Implementar rate limiting en API Gateway. Establecer alarmas de presupuesto en AWS Budgets.
Buenas prácticas de seguridad para AWS Lambda y FaaS
A continuación, presentamos un checklist de seguridad que todo equipo serverless debería implementar.
1. Gestión de secretos y variables de entorno
Nunca incluyas credenciales (API keys, contraseñas de BD) en el código o en el archivo de configuración de la función.
- Usa AWS Secrets Manager o AWS Systems Manager Parameter Store para almacenar secretos.
- Recupera los secretos en tiempo de ejecución (fuera del handler principal, para reutilizar la conexión).
- Activa el cifrado de variables de entorno con una KMS key.
2. Hardening del runtime y dependencias
- Utiliza runtimes oficiales y actualizados (Node.js 20, Python 3.12, etc.).
- Evita usar imágenes base
latest. Fija versiones específicas. - Implementa un Layer de seguridad que incluya herramientas de monitoreo (Datadog, New Relic) y agentes de seguridad (como AWS GuardDuty para Lambda).
- Escanea las dependencias en cada build del pipeline CI/CD.
3. Validación estricta de eventos y entrada
- Define un esquema para el evento esperado (JSON Schema, protobuf).
- Usa un middleware de validación (ej:
pydanticen Python,joien Node.js). - Rechaza cualquier evento que no cumpla el esquema con un error 400.
4. Principio de mínimo privilegio en IAM
- Crea roles específicos por función, no roles genéricos.
- Usa políticas inline o managed policies con recursos ARN específicos.
- Revisa periódicamente los permisos con AWS IAM Access Analyzer.
5. Monitoreo, logging y detección de anomalías
- Centraliza logs en Amazon CloudWatch Logs o en un SIEM.
- Activa AWS CloudTrail para auditar quién invoca las funciones.
- Implementa detección de anomalías: patrones de invocación inusuales, errores 403/500 repetidos.
- Usa AWS GuardDuty para detectar comportamientos maliciosos en funciones Lambda (ej: llamadas a IPs sospechosas).
6. Protección contra inyección de código y dependencias
- Evita
eval(),exec()ochild_process.spawn()con argumentos dinámicos. - Si usas contenedores para Lambda, escanea la imagen con AWS ECR Scan.
- Bloquea la descarga de paquetes externos en tiempo de ejecución (deshabilita
pip installonpm installen producción).
7. Seguridad en la red (VPC)
- Si la función necesita acceder a una base de datos o servicio dentro de una VPC, coloca la función dentro de la VPC.
- Usa VPC Endpoints para servicios AWS (S3, DynamoDB) sin necesidad de NAT Gateway.
- Limita el tráfico de salida con Security Groups y NACLs.
8. Manejo de errores y fallos
- No expongas stack traces ni mensajes de error internos en las respuestas HTTP.
- Implementa un manejador de errores global que registre el error en CloudWatch y devuelva un mensaje genérico.
- Usa DLQ (Dead Letter Queue) para eventos que fallan repetidamente, evitando bucles infinitos.
Caso práctico: Asegurando una función de procesamiento de imágenes
Imaginemos una función Lambda que se activa cuando se sube una imagen a un bucket S3. La función redimensiona la imagen y la guarda en otro bucket.
Paso 1: IAM mínimo
El rol de Lambda debe permitir:
s3:GetObjecten el bucket de origen (arn:aws:s3:::origen/*).s3:PutObjecten el bucket de destino (arn:aws:s3:::destino/*).logs:CreateLogGroup,logs:CreateLogStream,logs:PutLogEventspara CloudWatch.
Paso 2: Validación del evento S3
El evento S3 contiene metadatos como el nombre del objeto. Validar que el nombre no contenga ../ ni caracteres especiales. Asegurar que el tipo MIME sea de imagen (JPEG, PNG, etc.).
Paso 3: Protección contra inyección
Usar una biblioteca de procesamiento de imágenes (Pillow, Sharp) que no ejecute comandos del sistema. No usar os.system() para redimensionar.
Paso 4: Límites de concurrencia
Configurar la concurrencia reservada a 10 para evitar que un ataque DoS dispare el coste.
Paso 5: Monitoreo
Crear una alarma en CloudWatch que se active si la función falla más de 5 veces en 5 minutos.
[TIP] Usa AWS Lambda Power Tuning para encontrar el equilibrio entre rendimiento, coste y seguridad. A veces una función con más memoria (y por tanto más CPU) se ejecuta más rápido, reduciendo la ventana de ataque.
El futuro de la seguridad serverless
La seguridad en arquitecturas serverless y FaaS está evolucionando rápidamente. Herramientas como AWS WAF para API Gateway, AWS Shield para protección DDoS, y AWS Network Firewall para inspección profunda de paquetes están cerrando la brecha. Sin embargo, la responsabilidad última recae en el desarrollador.
Tendencias clave:
- Zero Trust para funciones: Cada función debe ser tratada como un host no confiable, incluso las internas.
- Seguridad como código: Integrar políticas de seguridad en el pipeline CI/CD (Infrastructure as Code + Security as Code).
- Machine Learning para detección de anomalías: Modelos que aprenden el comportamiento normal de una función y alertan sobre desviaciones.
La seguridad serverless no es un producto que se compra, es una disciplina que se practica. Desde la validación de eventos hasta la gestión granular de IAM, cada decisión de diseño impacta en la postura de seguridad. Adoptar estas buenas prácticas no solo protege tus datos, sino que también evita sorpresas desagradables en la factura mensual.
