This article is part of a two-part series:
- Part one - high-level overview, general security, frontend security
- Part two - backend security
First off before we dive into “how” to secure your serverless applications. Let’s first talk about “why” you need to secure serverless applications. As you can imagine, just because serverless is abstracting the compute resources doesn’t mean it’s abstracting all of the security considerations.
Why do I need to secure a serverless application?
Even in serverless world security should still be at the top of your mind. Serverless streamlined a lot and has helped allow everyone to move faster. However, when you can do more with less. People do more. That has resulted in an explosion of new services which fit into the serverless ecosystem. With the addition of these services we now need to pay attention to more surface area.
We are less vulnerable than a non-serverless environment, however that does not mean we are invulnerable. In a lot of cases, securing your serverless applications comes down to making sure that the small amount of buttons you should be pressing are actually pressed at all.
For example, a common data leak scenario which is constantly in the news stems from companies who have public S3 buckets which hold non-sensitive data such as PDFs, images, etc. This allows anyone with the URL to have access and if the list object permission is active on that S3 bucket it allows people to scan your buckets for file paths and steal even more data. Couple this with predictable human-made path names and you’re opening up your whole business to being scraped with a few lines of code. This is not an AWS problem, it’s a configuration problem. If the developers would have ensured the bucket was private or had better organization between sensitive and non-sensitive data this would not have been possible.
How do I secure serverless applications?
Okay so let’s imagine a common serverless application then go through how we should think about security.
Our application will be broken into a frontend and a backend.
The frontend consists of the following resources:
- S3 Bucket - website file storage (e.g. index.html, js/, css/)
- CloudFront Distribution - CDN (https, performance)
The backend consists of the following resources:
- Lambda functions - business logic
- API Gateway - REST API
- DynamoDB - NoSQL database
What about our AWS accounts:
- DEV - sandbox account for developers to develop new features
- QA - test new features
- PROD - user-facing
Alright so now with some context. Let’s jump into what areas we need to pay attention too when it comes to securing our serverless applications.
Due to having multiple AWS accounts, we need to ensure that we handle account management properly.
Creating AWS credentials for each individual developer on every AWS account.
Use a central AWS account where you define all of your AWS IAM users. Create IAM groups which have a series of cross-account IAM roles associated with the group, allowing developers to easily switch into other AWS accounts without passing around credentials.
To keep track of things taking place inside your AWS account you will want to leverage AWS CloudTrail which gives you audit logs on API calls inside your AWS account out-of-the-box.
If you want to get more advanced you can automatically create AWS Athena tables in the AWS Cloudtrail console, check out this article.
When it comes to S3 we will want to keep everything private.
Make all S3 buckets public. This is the quickest approach to getting something working, but quickly gets forgotten as things move from development to production.
Keep all S3 buckets private, even a website (more on this below).
For any asset storage (e.g. images, PDFs, etc.) we will want that S3 bucket to be private as well. Then we can create an API which will return a pre-signed URL that allows temporary access to our private S3 bucket holding our assets.
Amazon S3 has Server Access Logging which will log all requests made to your bucket and S3 Object Level Logging to CloudTrail which will log object-level API actions to AWS CloudTrail. We should turn these on as well.
AWS CloudFront Distribution
We will want to connect our AWS CloudFront Distribution directly to our AWS S3 bucket by using a CloudFront Origin Identity. This will allow traffic to our AWS S3 bucket only if it’s coming from our AWS CloudFront Distribution ensuring that all traffic to our website flows through a single point.
Serverless has made security much easier. However, you still need to devote energy to make your applications secure. Finally, a lot of security exploits with serverless related technologies come from misconfiguration which expose non-public information publicly. It’s been a problem long before serverless, but now we can simply press a couple buttons and let the fully managed power of serverless technologies do most of the work.
That covers one half of how to secure serverless applications, in the next article we will dive into how to secure your serverless application backend. Stay tuned!