While most articles about Lambda security focus on the actual Lambda code, it’s worth looking at the guardrails you can put in place around that code. In this article, I’ll go over three practices that should be considered table stakes.
Lambdas are incredibly powerful but they are, especially for non-compiled runtimes, almost too easy to modify. Anyone who has the correct access to the AWS Console can directly edit the source code of a function, and that new code will be executed at the next cold start invocation.
Code signing for AWS Lambda restricts the ability to make changes to the source code of a function. Once code signing is enabled for you can no longer edit the source in the console. You can only modify the code by uploading a signed ZIP file. There are four steps to enable code signing.
First, create a signing profile and specify how long the profile is valid for. The default value is 135 months which seems absurdly long but YMMV.
Next, use the ARN of the signing profile to create a signing configuration. This lets you specify that unsigned code should be blocked or a warning should be generated.
Next, go to the function you want to protect and edit its code signing configuration. Once this is done, your function can only be updated with signed code.
The last step is to create a signing job that will accept a Lambda S3 zip file, sign it and output a signed zip. This zip can then be deployed as you normally would. The first three steps must be done once per function while the last step happens each time you deploy new code. All steps can and should be automated via CloudFormation or Terraform.
Lambdas without versions have an ARN in the following form:
arn:aws:lambda:us-east-1:<account_id>:function:<function_name>
Once the Lambda is modified, any program calling the lambda will execute the new code. It's easier to manage Lambda deploys if you can decouple deploying from the releasing. Lambda versions and aliases can help us accomplish that.
When using lambda function versions, the lambda ARN will include the version number.
arn:aws:lambda:us-east-1:<account_id>:function:<function_name>:<version>
This allows you to pin a version to production (say version 4) while continuing to work on new development versions of the lambda. When a new version is ready to be promoted to production (say version 6) one could update all of callers of the function to use the new ARN that ends in “6” independent of the deploy process. Once a version is published it becomes immutable so that anyone calling a specific version will alway execute the same code.
But, this creates an extra step. Callers need to be updated anytime a new version of the lambda is available. It also means that the callers have more information about the lambda than they otherwise need.
Aliases provide a way around this issue. An alias points to a version and can be used in the ARN to reference the lambda. So, for example you can have an alias of the form
arn:aws:lambda:us-east-1:<account_id>:function:<function_name>:Production
This alias might point to version 4 and when version 6 is ready you can re-assign the alias to point there. No changes are required to any calling programs.
Both GitHub and CodeCommit offer guardrails to protect your main branch. For example, you can require Pull Requests (PR) to have a certain number of approvers or even specific reviewers. But even with these options code reviews can be ignored or done in a cursory manner. The sad state of code inspections was illustrated by a recent post by Forrest Brazeal claiming that serverless applications were unsafe because nothing stops them from accidental recursive invocations. When the author pointed out that code inspections could actually catch this the comment was marked as insightful! (Next I’ll point out that water is wet).
First, none of the options mentioned above are enabled by default. The default settings in GitHub allow pushing directly into main branch without a Pull Request. You may consider PRs and branch protection table stakes for source control, but they must be configured up front and forgetting to do so will leave main branch exposed.
Don't let your Lambda function cause downtime because you left main unprotected
Second, even if these options are enabled, they don't automatically ensure PRs will recieve quality reviews. At a recent study showed that less than 2% of PRs generated a single comment. This is a common culture issue and changing a company’s culture is usually a monumental task.
Enter Amazon CodeGuru Reviewer. This is one of the growing set of components of AWS’s AI-driven CodeGuru suite. When creating a repository in CodeCommit (or GitHub Enterprise) you can specify that Reviewer be automatically added to the set of reviewers for a PR. Once this is done, any PR on the specified branch (usually the main branch) will launch a Reviewer inspection.
From the AWS documentation: “Amazon CodeGuru Reviewer uses program analysis combined with machine learning models trained on millions of lines of Java and Python code from the Amazon code base and other sources.” Currently, there are 80 rules for Python and 91 rules for Java. You can view the full list of detectors for Python here.
For each language, the detectors are broken down by category including Security and Code Quality. An inspection run can take several minutes depending on the size of the PR. When it completes it will display any suggestions for improvement it found that looks like the following:
In addition to the quality of the review comments, Reviewer presents it’s finding in an emotionless, blameless manner. One of the pitfalls of human-generated code reviews is that the comments can be interpreted as insulting to the author. Reviewer provides an example of how to get objective comments on the code and not on the code author.
There are of course other code inspection tools such as ShiftLeft, SonarQube, and Codacy. Whichever tool you prefer, automated code review should be in your tool belt.
Most Lambda users know that there is only one knob to tune performance: the memory setting which controls both the memory and the CPU allocated to your function. There has been speculation that this setting also controls the amount of network bandwidth available to the function. At the AWS American Heroes Summit last month, the Lambda team definitively rejected this speculation.
AWS recently announced volume discount pricing for Lambdas. Up to a 20% discount is possible for high volume users which may change the inflection point for price between Lambdas and containers in some cases.