AWS Lambda function with an overly privileged execution role

Review excessive permissions in a Lambda execution role and restrict access to the actions and resources the function needs.

Description

A Lambda execution role supplies the permissions that function code uses to access other AWS services. Unnecessary broad permissions such as iam:*, or permissions involved in assuming another role or creating credentials such as sts:AssumeRole and iam:CreateLoginProfile, can increase the damage if the function is compromised.

The operations actually available depend on attached policies, resource scope, conditions, permissions boundaries, and other applicable limits. If a function needs powerful permissions, confirm the operational need and restrict the permitted targets and conditions.

Potential impact

  • A compromised function could misuse sensitive IAM actions available to its execution role.
  • Depending on effective permissions and other policies, an attacker might create additional credentials or use another role.
  • Sharing an overly privileged role across functions can increase the impact of an incident and make permissions harder to manage.

Remediation

  • Identify the actions and resources the function actually uses, then remove unnecessary permissions.
  • Use an execution role appropriate to the function and restrict resources and conditions where supported.
  • Review inline policies, managed policies, permissions boundaries, and other applicable limits together, then test that required functionality still works.

Examples

These Terraform excerpts illustrate the difference between two policies. The Lambda function, execution-role definition, and configuration that associates the function with the role are omitted.

Before

hcl
resource "aws_iam_role_policy" "lambda_privileged_policy" {
  name = "lambda-privileged-policy"
  role = aws_iam_role.lambda_execution_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ec2:Describe*",
          "iam:*"
        ]
        Effect   = "Allow"
        Resource = "*"
      }
    ]
  })
}

After

hcl
resource "aws_iam_role_policy" "lambda_scoped_policy" {
  name = "lambda-scoped-policy"
  role = aws_iam_role.lambda_execution_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ec2:Describe*",
          "s3:GetObject"
        ]
        Effect   = "Allow"
        Resource = "*"
      }
    ]
  })
}

Explanation:

  • Before: The policy allows iam:* on every resource. Check whether the execution role needs this breadth of access.
  • After: The policy removes iam:*, but retains Resource = "*" and broad read permissions. It is not yet a complete least-privilege policy. In particular, restrict s3:GetObject to the object ARNs in the required buckets.

References