1. Use fine-grained permissions for IAM execution role.
An AWS Lambda function’s execution role grants permission to access AWS services and resources. You provide this role when you create a function, and Lambda assumes the role when your function is invoked. It defines what your function can do.
Always allow only needed actions on required resources. For example, if function needs to read data from particular S3 bucket, create policy that allows only reads from that bucket. Avoid using * on Action or Resource. Example policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::MY-EXAMPLE-BUCKET/*"
]
}
]
}
2. One Lambda = one role.
You should always set up a one-to-one relationship between your AWS Lambda functions and their IAM roles, meaning that each Lambda function should have its own IAM execution role. This will assure that each individual function has always the minimal amount of access required to perform its tasks.
3. Write secure code.
If your code is written in an insecure manner, the application can be vulnerable to traditional application-level attacks, like Cross-Site Scripting (XSS) or SQL Injection. Check OWASP Serverless Top 10.
4. Ensure no vulnerabilities in dependencies.
It is equally important that you track vulnerabilities in application dependencies. For application dependency vulnerability scans, there are several commercial and opensource solutions, such as OWASP Dependency Check, that can integrate within your CI/CD pipeline. It’s important to include all your dependencies as part of your version control software repository.
5. Use API Gateway to expose your function.
API Gateways provide DDOS protection, rate limiting and integration with authentication services like AWS Cognito. Never expose you Lambda function directly to wider audience, AWS API Gateways is good (but not only) choice.
6. Clean /tmp folder.
The /tmp directory is the only place you can write to disk on a Lambda function invocation. When an AWS Lambda function is triggered, a temporary execution environment is created. The Lambda function is then run within the environment. Once a function has completed executing, the execution environment might be kept around, with your /tmp directory, and used again if the Lambda function is triggered again. It is recommended that functions delete their temporary files before ending execution. There are cases when you want to leave some cached files to speed up executions, but always do it intentionally. Never store there any sensitive data.
Also, never put sensitive information into metadata, such as function names and tags.
7. Do not store secrets as unencrypted environment variables.
Your Lambda function might need to access other AWS resources or some external services. Always try to use IAM roles first, to give access to AWS services (see point 1). If you really need to pass secrets to AWS Lambda function never store it in unencrypted environment variables. Instead, use solutions like:
- encrypting it using KMS,
- storing secrets in Secret Manager,
- storing secrets in SSM Parameter Store.
You can find out more about secrets management in this post.
8. Allow storing logs in CloudWatch Logs.
Provide lambda execution role with the appropriate permissions to push logs from your code to CloudWatch Logs, ensure you allow the ability to create a log group, log stream and put events, as shown below.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:region:accountId:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
" arn:aws:logs:region:accountId:log-group:/aws/lambda/functionName:*"
]
}
]
}
Of course, you can use any other logging solution.
9. Watch out what you are sending to output.
When you use the print
method in your Python code, or any logging library in any language that writes to stdout
or stderr
it is send to CloudWatch Logs. This means if you accidentally print your database password it will be visible in logs.
10. To VPC or not to VPC
Lambda can run outside or inside VPC. Each option brings some implication. This decision tree can help you decide when to deploy your Lambda function in a VPC:
If you deploy your function into VPC you need to create a security group.
It will control the function’s access to the resources in the subnets and on the Internet. Create strict rules, also for outbound connectivity! For example, if your Lambda function communicates with RDS create outbound rule that allows connection to RDS security group on database specific port. Check also how to access DynamoDB from AWS Lambda.
Do you want to learn more about AWS Lambda?
Materials
Whitepaper: Security overview of AWS Lambda
Serverless Lens in AWS Well-Architected Tool