Skip to main content

Serverless - one dedicated IAM role per function

Need

Enforce separate IAM roles for each Lambda function

Context

  • Usage of Terraform for Infrastructure as Code (IaC)
  • Usage of AWS SDK for interacting with Amazon Web Services
  • Usage of AWS IAM Roles for managing access and permissions in AWS services
  • Usage of AWS Lambda Function for serverless computing and event-driven applications

Description

Non compliant code

provider "aws" {
region = "us-west-2"
}

resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_lambda_function" "lambda_function1" {
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name1"
role = aws_iam_role.iam_for_lambda.arn
handler = "exports.test"
}

resource "aws_lambda_function" "lambda_function2" {
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name2"
role = aws_iam_role.iam_for_lambda.arn
handler = "exports.test"
}

In the above Terraform code, we have defined an AWS IAM role iam_for_lambda and two AWS Lambda functions lambda_function1 and lambda_function2. Both of these Lambda functions are using the same IAM role iam_for_lambda for execution.

The issue here is that if we need to add any specific permission to lambda_function1, we would add it to the IAM role iam_for_lambda. However, since lambda_function2 is also using the same IAM role, it will also get the same permissions. This can lead to unnecessary access and potential security risks.

The best practice is to have separate IAM roles for each Lambda function. This way, we can manage the permissions for each function separately, reducing the risk of unnecessary access.

Steps

  • Create a separate IAM role for each Lambda function
  • Update the 'aws_iam_role' resource block to define a unique name for each IAM role
  • Update the 'aws_lambda_function' resource blocks to use the respective IAM role ARNs for each Lambda function

Compliant code

provider "aws" {
region = "us-west-2"
}

resource "aws_iam_role" "iam_for_lambda1" {
name = "iam_for_lambda1"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_lambda_function" "lambda_function1" {
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name1"
role = aws_iam_role.iam_for_lambda1.arn
handler = "exports.test"
}

resource "aws_iam_role" "iam_for_lambda2" {
name = "iam_for_lambda2"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_lambda_function" "lambda_function2" {
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name2"
role = aws_iam_role.iam_for_lambda2.arn
handler = "exports.test"
}

The updated code creates a separate IAM role for each Lambda function. This is done by defining two aws_iam_role resource blocks, each with a unique name (iam_for_lambda1 and iam_for_lambda2).

The aws_lambda_function resource blocks are then updated to use the respective IAM role ARNs for each Lambda function. This is done by setting the role attribute to the ARN of the respective IAM role (aws_iam_role.iam_for_lambda1.arn for lambda_function1 and aws_iam_role.iam_for_lambda2.arn for lambda_function2).

This approach ensures that each Lambda function has its own dedicated IAM role, allowing for more granular control over permissions. This mitigates the risk of permissions being unintentionally shared across multiple functions, enhancing the security of the infrastructure.

References