Serverless architectures make it possible to build complex application systems without having to worry about managing the infrastructure. The cloud provider takes care of aspects such as availability, provisioning and scaling. The focus of application development is on the implementation of functionality in the form of detached functions. The bottom line is that the approach is also cost-effective – provided the development team has done their homework on architecture and software design.
Thanks to the Managed Runtime Model, maintenance, updates and patches for the entire (virtualized) hardware and software stack are a thing of the past. The team can focus 100 percent on the implementation of the business logic of the application.
That’s the theory. In practice, it’s not as trivial as cloud providers like to make it out to be. Splitting a monolithic application into many small functions, which in turn are highly distributed, loosely coupled, and interacting asynchronously with other functions or cloud components, results in an extremely complex system on many levels that is not easy to master. The following figure shows an example of a serverless scenario for saving an image, including the associated description in a virtual travel diary:
One application, hundreds of functions
In the world of serverless functions, it is not uncommon for an application to consist of hundreds of functions, each of which is relatively trivial on its own. Their interaction, on the other hand, results in a highly complex and – “thanks” to the cloud environment – a fragile overall system.
The individual functions are usually activated by dedicated events, including the associated payloads. After the work is done, for example storing images in an object store or saving data in a NoSQL database, they often trigger other functions or cloud components – also with suitable events. The end result is a loosely coupled, asynchronously working system. A joy for every architect.
In order to guarantee sufficient security for such a system, a rethink is required. The attack surface is significantly broader than in a monolithic application, the individual points of attack are distributed over a large number of different components.
Hundreds of functions, one overall view
Despite the many small, often trivial functions, the overall view of the system plays a decisive role when considering security-related aspects. What points of attack do the individual components of the system offer and what additional points of attack result from their interaction? What data does the system process? How sensitive is the data and what is its value? What would be the damage if they became public in the event of a breach of the security policy (aka breach)? The answers to all of these questions show potential points that need to be addressed in order to ensure the desired level of security for the overall system.
This in turn raises the question of which points the developers of the application are responsible for and which the cloud provider is responsible for. The following diagram shows the separate responsibilities based on the “Shared Responsibility Model for AWS Lambda”.
A nearly identical picture emerges for other cloud providers.
The following best practices for serverless security reflect the most important starting points for implementing a security policy. The following figure shows where the best practices come into play within a serverless architecture:
Extended App Monitoring
An overall picture of the interaction of the components involved in a use case is essential. Intensive monitoring and auditing at the serverless function level helps to create this picture and to react in a targeted and automated manner in the event of anomalies. Anomalies can be, for example, call paths that are not intended in the form or incomplete, unexpected or corrupted data in incoming events.
This article comes from the iX Developer special issue “Developing secure software”. On 156 pages, it deals with topics such as web application security, code analysis methods and cloud security. The focus on DevSecOps shows methods, tools and maturity models.
For specific programming languages, one article aims to help track down and avoid memory errors in C++, and another explains Rust’s security concepts. Anyone developing with Java will find an overview of the changes to security from Java 11 to Java 17.
The topic of cryptography goes from the basics to the pitfalls when integrating cryptographic methods in your own applications to the outlook for post-quantum cryptography.
As a best practice, teams should implement intensive and secure logging at the serverless function level. For reasons of performance, log information should be written asynchronously and collected in a central log for comprehensive evaluation. Additional context information such as correlation IDs and tags help with targeted monitoring and make it easier to find problems and their causes. Tools can visualize the metrics and log information of individual serverless functions as well as their interaction. Thresholds can be used to trigger alarms, send notifications and automatically initiate countermeasures.
Securing function dependencies
As in non-serverless-based development, it is important to regularly check the dependencies of the individual functions of third-party libraries for vulnerabilities. The special challenge arises in the environment of serverless applications due to the large number of functions and the frequency with which they are changed. The famous Dependency Hell reaches a new level of complexity in the serverless world.
It has been established as best practice to fully automate the required checks and to carry them out as part of the continuous integration and deployment lifecycle. Tools to ensure continuous code quality and code security such as Snyk, Codacy or sonarcloud can be seamlessly integrated into the CI/CD pipeline and enable automatic security scans at various levels.
Alternatively offers this quelloffene Framework Serverless appropriate plugins.