A few years ago, cloud computing was only about spinning up virtual machines. The ability to add more on demand when the load increased fundamentally changed the way we think about uptime and reliability. Software development patterns evolved, andisolation and immutability became cornerstones with the emergence of microservices.
At that time, the cloud offering exploded to respond to these new demands. Along came AWS Lambda, providing infinitely scaling code execution in isolated, immutable environments. Other vendors promptly followed with competing products. The architectural pattern has many names, including, Function as a Service (FaaS) or Serverless, which seems to have stuck a little more.
One would think that in the age of the cloud, where virtually infinite computing resources are available, shortcuts would no longer need to be taken for the sake of performance. It turns out we’re not quite there yet. Data access remains a significant bottleneck. When a lambda function is called, it needs to access the code, create an isolated container and run it. This takes a few hundred milliseconds – a few eternities.
To speed-up the process, vendors use several tricks:
- Use node affinity, reducing the amount of network traffic to obtain the code. Depending on the volume of calls performed to the API, the probability of hitting the same machine multiple times varies. Low-volume calls require less patience to exploit.
- Reuse the execution containers. This breaks the promised isolation. The code may not run in a clean state on every call.
Andrew Krug and his team went to great lengths to perform due diligence on many vendors for the benefits of everyone and highlighted several vectors that can be exploited. The code to test the security features is publicly available.
- The filesystems are sometimes writable, either globally or locally, such as /tmp, allowing potential persistence in case of reuse. Vendors should likely prevent this, or make it optional for applications that need to write files.
- Access tokens are available within the containers, allowing access to other resources if the privileges are not restrained properly. As tempting as it is to use the same roles for all of your applications, limiting access to a strict minimum is the best mitigation.
- Runtime timeouts are not always available or encouraged enough, giving too much time for attackers to exploit.
The isolation provided by the serverless architecture is a clear benefit from a security perspective. The attack surface can be limited to a rather short list compared to other environments. Yet, although these service providers use names from functional programming like Lambda and Function. Don’t be fooled: the code you execute is not a pure function. It likely relies on external data and has privileges on it. A remote code execution vulnerability or other types of injections in your code can still cause damage.
Relying solely on the platform-isolation features is an insufficient security measure. Adequate security assessment of the code running under these serverless architectures is still required and additional mitigation should be considered.