Serverless Best Practices on AWS
Do your serverless deployments go like this?
It’s so easy to quickly deploy serverless resources. Because of this, we should follow best practices to protect our resources, applications, and cloud service provider accounts. Here are some best practices for you to consider.
1. Keep Functions Small
A serverless function should perform a specific function. Similar to a function or method in any code should do one thing (e.g., increment a counter, transform data, etc.), a serverless function show perform a logical function. For example, you would create one serverless function for validating a login, another for validating a login session, another for deactivating a login session. Having a serverless function perform more than one thing makes it vulnerable to bugs and makes it more difficult to maintain.
2. Organize Functions in a Group (i.e., Use Microservices)
Microservices allows us to contain data stores and functions into a maintainable group. The microservice will follow a contract that limits what it can and cannot do. For example, an account microservice will allow creating, updating, and deleting user accounts. This microservice should never modify any data outside of the user account data store. Furthermore, it will have a specific application programming interface (API). This allows other microservices to interact with the user account serverless functions in a consistent way without having to modify any of its user account data stores.
3. Use Different Stacks for Different Resources
AWS allows us to use CloudFormation stacks when deploying resources, and each Serverless Framework configuration deploys one CloudFormation stacks. We should aim to have one stack per resource type. For example, our user account microservice could have: database stack (to store account metadata in DynamoDB), identity provider (IdP) stack (to set up and maintain user sessions with Cognito), function stack (to deploy Lambda functions that provide the user account microservice API), and object store stack (to capture user account profile pictures in S3). This allows you to update a resource type without disrupting another resource type. For example, if you make an error in a functions stack deployment, your other stacks remain unaffected.
4. Select an Appropriate API
AWS offers three types of APIs: HTTP APIs, REST APIs, and GraphQL APIs. Each API has different benefits. HTTP APIs use API Gateway, are lightweight and natively support OpenID and OAuth. REST APIs use API Gateway, are fully featured REST APIs and provide additional security features. GraphQL APIs use AppSync, use a simple, but string query language, and integrates with DynamoDB databases and Elasticsearch Service data aggregator. API Gateway HTTP and REST APIs are best for interactions between APIs (or microservices) and providing external applications access to your applications API. AppSync GraphQL APIs are best between client and backend integrations within the same application (of course your client can still use an API Gateway API too.)
5. Use the Principle of Least Privilege in Your Serverless Functions
All your resources should have the smallest set of IAM permissions. For example, a serverless function that reads a DynamoDB table should only have the read action for that one DynamoDB table. You should avoid using an asterisk “*” when defining privileges whenever possible. If you Lambda function is ever compromised and it uses asterisks such that every DynamoDB is accessible and every action is allowed, then a hacker can read and delete all database data.
6. Set up a CI/CD Pipeline
When you are first developing an application, deploying from the command line interface (CLI) is okay. Ideally before you get to deploying to production, you should be using a CI/CD pipeline to deploy your code. You can use services such as Serverless Framework Pro, GitHub Actions, SEED, and many others. CI part of the pipeline allows you to run linting checks, unit tests, and many other automated checks before allowing a pull request to merge. The CD part of the pipeline allows you to automatically deploy your serverless application whenever a PR is merged or a branch is updated. Using a CI/CD pipelines removes human error and introduces repeatability in your process.
7. Monitor Your Application
We should use services, such as Dashbird, to monitor our serverless resources. There may be so many resources and they may be used so much that it would be difficult to manually check them for errors. Monitoring services can report health, longer executions, delays, and errors. Having a service that tells us when our serverless application and resources are having issues helps us to find and fix issues faster.
8. Audit Your Cloud Provider Account and Resources
In addition to monitoring, we want to audit. Monitoring tells when when something stops working or is having issues. Auditing tells us when our resources deviate from a known configuration or are improperly configured. We can use services such as AWS Config to create rules that audit our resources and their configurations. Config also has some predefined conformance packs that help us implement best practices. Here are some to consider:
- Operational Best Practices for Amazon DynamoDB
- Operational Best Practices for Amazon S3
- Operational Best Practices for AWS Identity And Access Management
- Operational Best Practices for AWS Well-Architected Framework Reliability Pillar
- Operational Best Practices for AWS Well-Architected Framework Security Pillar
- Operational Best Practices for Serverless
9. Audit Your Software Dependencies
We also want to audit our software dependencies. Just because we no longer have a server, it does not mean we are free from “patching.” We want to make sure any software dependencies we define are up-to-date and have no known vulnerabilities. We can use services such as GitHub Dependabot and Snyk to keep us informed the software packages that need updating.
Your mileage will vary depending on your business and technical requirements, the complexity of your application, and your cost and schedule. These best practices are aimed to guide in the right direction; they are based on the “Serverless Security” book.
Before You Go
Join my mailing list to receive updates about my writing.
About the Author
Miguel is a Principal Security Engineer and is the author of the " Serverless Security " book. He has worked on multiple serverless projects as a developer and security engineer, contributed to open-source serverless projects, and worked on large military systems in various engineering roles.
Originally published on Medium.com