Security in Serverless
Step by step
Serveless infrastructure became popular. Very popular. It’s almost viral =) There are some good reasons for it: serverless approach is cost-effective, scalable and easy-to-deploy. The last one is at the same time a kill-feature and the weakest link: it’s so easy to push a few buttons or write a simple .yml manifest, so people have tendency to forget that majority of default settings are very unsecure. This short article contains five steps to ensure that your Serverless infrastructure is well protected.
Cloud provider: AWS
Serverless deployment framework: serverless.com
Step1: entrance by invitation only. Or let’s add authorisation.
There are two very important things to remember about Amazon API Gateway:
- It’s public.
- By default there is no authorization. At all: you wrote Lambda, you connected it to DynamoDB, you deployed it together with API Gateway — the whole World can access your data.
So, it’s really nearly impossible to underestimate how important it is: always add authorization at the very first stage of developing your Serverless project.
Currently Amazon API Gateway supports both API keys and Custom Authorizers. Let’s take a look on Authorizers first. There are two options: AWS Cognito and Lambda-based. Second one allows you to use BasicAuth, third party providers like Auth0 and etc.
As it quite obvious from it’s name, Lambda-based custom Authorizer is essentially a Lambda function, which invokes first every time someone calls an API endpoint. If you are using serverless.com framework, you can configure Authorizer in the same project:
And then - use authorizerConfig notation to attach custom Authorizer to your Amazon API Gateway endpoint.
Step2: DDOS protection. API keys, Usage Plans and Throttling.
As was mentioned before, another option for authorization at Amazon API Gateway is API keys. When you are choosing between the custom Authorizer and API keys, there are some pros and cons to be considered:
- Initial setup of API key is very simple: no Cognito pool or Lambda required.
- API keys solution are not as scalable as custom Authorizer: you have to create key for every user.
In many situation it makes sense to combine both API keys and custom Authorizer. Authorizer will give you secure, granular and scalable authorization, API keys — will help to protect your project against DDoS.
How? Very easy:
- Create API key per client
- Attach this key to the Usage Plan
- Configure Throttling for this Usage plan
- Associate Usage plan to API gateway endpoint.
If API key will be compromised or your client\partner has a malfunctioning service, which generates 10000 requests per second, you will be safe =)
Quota will be handy, in case you want to limit amount of calls from the certain API key per day, week or month.
Step3: don’t play with my endpoint. AWS WAF.
AWS WAF supports association with Amazon API Gateway. This is just awesome: you can protect endpoints with custom or managed ACL rules. Just follow AWS tutorial or purchase your ACL via AWS Marketplace.
It’s all quite easy if you are invoking Lambda functions via API Gateway. But it’s becoming slightly more complex, if you want to put Fargate\ECS container behind it. Yes, AWS introduced VPC integrations a couple month ago, but unfortunately only Network Load Balancer is supported. If you wish to use Application Load Balancer (and in many cases you are), you still have to:
a) make your Application Load Balancer public
b) use integration type: HTTP at your API Gateway
In this case you should have one more WAF between your API Gateway and Application Load Balancer. Firstly, it will protect your public container. Secondly, you can configure the rule, which only allows traffic from API Gateway to pass trough.
Step4: keep your secrets.
There are several options to secrets for your Lambda functions:
- Lambda environment variables. Used to be the worst options and well-known anti-pattern, but now Lambda functions support KMS encryption for environment variables. However, storing environment variables values in plain text of your serverless.yml file is still a horrible idea =) To avoid it, you can store variables in AWS Parameter store or AWS Secret Manager and use serverless framework functionality to obtain values during deployment.
- AWS Systems Manager Parameter Store allows you to encrypt variables with KMS keys and obtain values via SDK calls from your Lambda function.
- AWS Secret Manager provides the same functionality as AWS Parameter Store. But it has a nice feature of secret value rotation and integration with AWS RDS. However AWS Secret Manager price per secret is higher comparing with AWS Parameter Store. You choice.
Step5: final touch.
Serverless.com framework by-default creates a separate S3 deployment bucket for every project. To keep it tide and secure, it’s a good practise to have one deployment bucket for all projects. And encrypt it, just in case =)