Securing AWS Lambda

AWS Lambda can make your environment more secure than older deployment patterns--assuming you take security seriously and implement it in a secure way.

AWS Lambda makes security easier because you no longer have to manage OS hardening, admin rights, SSH, and segmentation. You still have to manage configuration and application code. The most important aspect of AWS Lambda security is the principal of least privilege.
"Every program and every privileged user of the system should operate using the least amount of privilege necessary to complete the job."
— Jerome Saltzer, Communications of the ACM
Least privilege dictates that we apply the smallest possible privilege so that it can function correctly, but can do nothing else.

Least privilege must apply to your application and its resources, function, persistence layer (S3, DynamoDB, etc.). AWS IAM roles are the primary control plane and should enforce least privilege.

Although least privilege is critical, it’s rarely achieved, making it a security "unicorn".

Let's look at an example. Suppose you want to write a simple function to read a file from S3:

var s3 = new AWS.S3([apiVersion: '2006-03-01']);
var params = [Bucket:'myBucket', Key:imageFileName];
var file = require('fs').createWriteStream('/tmp/gile.kpg');
s3.getObject(params).createReadStream().pipe(file);

A typical developer, more concerned with speed than security will write an IAM policy like this:

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:*"],
        "Resource":
            ["arn:aws:s3:::*"]
}

This IAM policy allows all actions on all s3 buckets. It gets the job done from the developer's perspective. The code will run, and not fail or give errors because of lack of permission. However, it is the antithesis of least privilege. It is most privilege.

We can start to move towards least privilege by specifying a single S3 bucket, instead of every s3 bucket in the world. If you partition your data into multiple buckets, making this one change means that if your function or role are compromised, only one bucket's worth of data could be affected.

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:*"],
        "Resource":
            ["arn:aws:s3:::myBucket/*"]
}

When trying to craft least privileged policies in AWS IAM, you should avoid the asterisk for both Resources and Actions. We have already gotten the Resource section to least privilege. But the Action section still have an asterisk.

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:GetObject"],
        "Resource":
            ["arn:aws:s3:::myBucket/*"]
}

This is finally a least privileged policy. An injection attack into this code Would only be able to read files from this particular bucket. The attack can’t read files from any other bucket, and can’t write to or delete the bucket. That will significantly reduce what an attacker can do.

So this is a simple example but we all know in the real world developers will cut corners to make deadlines. This is one reason why achieving least privilege is so hard.

Security is the opposite of development. Security is about controls and limits. Development is about creating and enabling. A developer’s instinct is to enable, and remove obstacles, and it can therefore be challenging to ask them to apply security restrictions at the same time.

Other reasons least privilege is hard:

  • Security takes time, developers don’t have time
  • Security gets in the way, so the easiest thing to do is wildcard it
  • Lack of visibility, to even know what permissions you need
  • Lack of granularity of access controls
  • Lack of awareness or mindfulness to the problem
AWS Lambda makes least privilege even harder because:

  • You have many (many) more resources
  • Your developers are updating them more
Serverless does make least privilege easier in this way. When compared to a large monolith, microservices implemented as serverless AWS Lambda functions  require many fewer privileges.

Training developers in AWS Lambda security best practices is essential to achieving least privileges. While security may be difficult for most developers, You can't take the whole thing out of their hands entirely so that someone else owns it. That puts that someone in the critical path--not a good place to be. Automated tools can play an important role. But at the end of the day, it remains important to train developers to think about security. I recommend the following best practices:

  • Look for low-hanging fruit
    • Such as an asterisk in any permissions
  • Try to do this as you develop
    • Easier in tandem with the development process
  • Run tools
    • All the training in the world won’t will close the gap as much as running a few tools, so definitely do both
  • Focus on permissions from the bottom up
    • Start from the assumption that the function needs nothing


Comments

Popular posts from this blog

Authentication for RESTful APIs

How to build a simple RESTful API with Flask

Security From Happiness