Zero trust and serverless – Serverless and Security



Zero trust and serverless

Zero trust is often touted as the next big thing in network security. Buzzwords and hype aside, you will find that it is a natural fit for applying security to distributed, serverless systems. Indeed, zero trust is often the de facto methodology for securing serverless applications. Approaching application security with a zero trust mindset supports the development of good habits, such as inter-service message verification and internally accessible API security.

You cannot simply move from a castle-and-moat model to zero trust. You first need a supporting application architecture. For example, if your API, business logic, and database are running in a single containerized application, it will be very difficult to apply the granular, resource-based permissions needed to support zero trust. Serverless provides the optimum application architecture for zero trust as resources are naturally isolated across API, compute, and storage and each can have highly granular access control in place.

The principle of least privilege

Identity and access control is essential for an effective zero trust architecture. If the security perimeter must now be around every resource and asset in your system, you are going to need a highly reliable and granular authentication and authorization layer to implement this perimeter.

As your application resources interact with each other, they must be granted the minimum permissions required to complete their operations. This is an application of the principle of least privilege, introduced in Chapter 1.

Let’s take a relatively simple example. Suppose you have a DynamoDB table and two Lambda functions that interact with the table (see Figure 1-11). One Lambda function needs to be able to read items from the table, and the other function should be able to write items to the table.

You might be tempted to apply blanket permissions to an access control policy and share it between the two Lambda functions, like this:

{

“Version”: “2012-10-17”,

“Statement”: [

{

“Sid”: “FullAccessToTable”,

“Effect”: “Allow”,

“Action”: [

“dynamodb:*”

],

“Resource”: “arn:aws:dynamodb:eu-west-2:account-id:table/TableName”

}

]

}

However, this would give each function more permissions than it needs, violating the principle of least privilege. Instead, a least privilege policy for the read-only Lambda function would look like this:

{

“Version”: “2012-10-17”,

“Statement”: [

{

“Sid”: “ReadItemsFromTable”,

“Effect”: “Allow”,

“Action”: [

“dynamodb:GetItem”,

“dynamodb:Query”,

“dynamodb:Scan”

],

“Resource”: “arn:aws:dynamodb:eu-west-2:account-id:table/TableName”

}

]

}

And a least privilege policy for the write-only Lambda function would look like this:

{

“Version”: “2012-10-17”,

“Statement”: [

{

“Sid”: “WriteItemsToTable”,

“Effect”: “Allow”,

“Action”: [

“dynamodb:PutItem”,

“dynamodb:UpdateItem”

],

“Resource”: “arn:aws:dynamodb:eu-west-2:account-id:table/TableName”

}

]

}

Fortunately, the underlying permissions engine used by all AWS resources, called AWS Identity and Access Management (IAM), applies a deny by default stance: you must explicitly grant permissions, layering in new permissions over time as required. Let’s take a closer look at the power of AWS IAM.

Leave a Reply

Your email address will not be published. Required fields are marked *