A few months ago, we wrote a piece on “The Continuum of Cloud Native Topologies” that covered the various technologies and deployment models within this universe of cloud native. At the far right of the continuum, prioritizing simplicity and agility above compatibility and control, was serverless. Serverless technologies like AWS Lambda, Google Cloud Functions, and Azure Functions, abstract away nearly all infrastructure concerns and provide a simple execution environment apps with tightly defined tasks and specific designs.
We first added support for serverless in Twistlock 2.3 by introducing scanning of serverless images for vulnerabilities, both as part of the CI process and within provider accounts. We have many customers using serverless today, and it’s been interesting to observe how this technology is used in the real world. Like any technology, it’s not a panacea, but serverless provides some differentiated advantages relative to running an app in a container environment where you manage more of the infrastructure.
For example, scenarios in which discrete actions are taken to analyze or transform data on demand are well suited for serverless functions. One of these customer is a top global insurance company and uses Lambda in precisely this manner to do process of claim data forms. For tasks like this that are tightly scoped, have specific triggers, and don’t need to persist session or data, serverless can provide a very simple experience for developers to go from code to execution with almost no friction. This insurer uses functions as a complement to their container environment, offloading some of these batch jobs to serverless functions, while running apps that require more control, configuration, and compatibility in containers.
This heterogeneous approach to containers and serverless is what we see across an increasing number of our customers. Our plan has always been to provide our full set of platform capabilities for serverless and I’m proud to announce that we’re now making our industry leading runtime defense capability available to protect serverless functions as well. Obviously, the underlying technical platforms are different, as are the CI/CD processes used to push apps into functions, so this blog will go through some of those differences and how our new Serverless Defender works.
In a ‘traditional’ container environment, Twistlock Defender runs as a container on a node where you’re running other containers. Defender uses existing kernel capabilities to get a near real time view of runtime data to feed our process, network, file system, and system call sensors. We use that data to generate models of each image and correlate those models back to the digests of the images, and then look for anomalies relative to what the models predict. This allows us to automatically prevent a web server container from running netcat, without having to have netcat on some kind of blocked list or an admin having to manually specify that only httpd should run. We automatically learn what’s normal and prevent what’s not based on these models.
In a serverless world, the platforms intentionally don’t allow ISVs or customers to run anything with elevated access to the hosts. Indeed, one of the fundamental concepts with serverless is that you don’t know or care about the host at all. There’s no concept of being able to run a ‘sidecar’ type Defender that protects all the given functions on a given node – there’s no concept of a node at all and certainly no ability for you to run anything outside that tightly defined box that functions exist in. Thus to protect a function, you have to be inside the function.
Thus, our Serverless Defender is quite different from our Container and VM Defenders. In those architectures, Defender can run multiple processes, store data, and basically assume that it has a ‘normal’ set of computing capabilities. Serverless Defender, on the other hand can make none of these assumptions and instead is really just a small shim that takes a minimal configuration from Console, enforces it at runtime, and logs to normal serverless facilities like CloudWatch.
Basically, Serverless Defender is a small init binary that starts when your function starts, immediately starts your actual function code, and continuously ensures that only that normal function code is allowed to execute. Your code never changes, it’s just not the default init process in your function any longer. This architecture yields an extremely efficient result – the overhead of Twistlock’s defense is ~4ms per process invocation (a relatively rare event in a function anyway), and <10KB RAM.
Being inside a function is a marked change from our approach for containers. We’ve always had a design mantra of ensuring that nothing we do requires you to change your images or the code you use to deploy them. With serverless though, there’s no way to protect a function without changing it to inject the Defender into it, so we spent a lot of time making this process as smooth and natural as possible.
Instead of having to load some Twistlock library into your dev environment and not having a way to cleanly debug your functions separately, we took a different approach. Specifically, you simply build your functions as you always have, and then run our twistcli tool to automatically do the rest. This means that your dev environment remains exactly as it is today, you do not need to manually add any Twistlock binaries into your functions’ zips, and you can always test and debug your app without any Twistlock components present simply by running a function version that hasn’t been embedded.
Once your function has had Serverless Defender embedded within it, you leverage existing platform aliasing versioning concepts to manage upgrades and debugging. For example, you may choose to have aliases to differentiate between a protected version and an unprotected version to simplify debugging during test but always use an alias like production-my-function to point at the protected version in production.
Because twistcli automatically creates a new build of each function you use it to embed Serverless Defender within, it’s easy to manage versioning and deployment according to your own needs and preferences. We’ve also designed the flow to be easy to automate around, so it’s simple to embed into existing CI processes. In fact, you’ll probably want to call twistcli twice in each CI job – once to scan the image and fail the build if vulnerabilities are detected above your threshold, and then again at the end to embed Serverless Defender.
Defense policies are configured centrally within the Console, of course. Policies target functions by simple regex matching of names so it’s easy to have consistent policies that span multiple functions without having to change them each time you rev the function. Because policies are defined centrally, developers aren’t responsible for setting them and can’t override them, so your security team can ensure that control requirements are met across the environment.
Functions are even more ephemeral than containers and some functions exists for mere seconds – or even less. Thus, every aspect of Serverless Defender has to be optimized for such an environment and logging is one of the most critical areas to consider. Most customers want to centralize security logging and analytics, so Serverless Defender always attempts to log directly back to Console, where data can be viewed in the existing Console UI and alerts can be sent to all our alerting providers like email, JIRA, Slack, and syslog.
I specifically use the term ‘attempts’ though because some functions may exist so briefly that the time required to establish a connection to Console exceeds their natural life. Because we’ve optimized Serverless Defender for all types of serverless scenarios, we also always log to the cloud provider’s native logging facilities, like CloudWatch. Thus, even for very short lived functions, there’s always an audit trail available and usually this trail also exists in Console.
As serverless functions become increasingly mainstream components of cloud native architectures, it’s critical to have a security platform that spans across your entire estate and protects them alongside your containers and VMs. Twistlock’s approach delivers that single, unified platform providing cloud native firewalling, vulnerability management, compliance, and now runtime defense across all your cloud native assets from VMs to containers to orchestrators to serverless functions. While this single, API accessible Console spans all these environments the specific defense mechanisms and architectural approaches are turned for the nuances of each deployment type while all policy and alerting is centralized and open. We’re proud to add serverless runtime to this set of capabilities and would be happy to show you a demo of how it can help protect your environment.
Related Serverless Security Posts:
Follow us on Twitter
Follow us on Twitter for real time updates on the cloud native ecosystem, Twistlock product, and cloud native security threats.
Docker Security Best Practices: 2018 Wrap-UpRead the Blog
Open Source Cloud Discovery Tool for Visibility Into Cloud Native PlatformsRead the Blog
The Evolution of Container Security, 2013-TodayRead the Blog
Why Automation is the Crucial Ingredient in Microservices SecurityRead the Blog
Best Practices for Compliance in a Cloud-Native EnvironmentRead the Blog