AWS Lambda Permissions: Resource-Based Policies vs. IAM Roles
Tags: aws, serverless, lambda, security
Published: 2023-11-04 18:08:22

When it comes to managing access permissions for your AWS Lambda functions, AWS provides two primary methods: **resource-based policies** and **IAM roles**. Each method has its own set of use cases, benefits, and limitations. In this article, I'll delve into the details of Lambda resource-based policies and IAM roles, compare them, provide examples of each, and offer guidance on selecting the best approach in line with AWS best practices and the AWS Well-Architected Framework.

**What is a Lambda Resource-Based Policy?**

A Lambda resource-based policy is an access policy attached directly to a Lambda function. This policy defines which entities (principally AWS accounts and other AWS services) can invoke your Lambda function and what specific actions they can perform. It's a straightforward way to grant access to your Lambda function without having to manage separate IAM (Identity and Access Management) policies or roles.

**Example of a Lambda Resource-Based Policy:**
Imagine you want to allow another AWS account to invoke your Lambda function. Here's a snippet of what that resource-based policy might look like:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-west-2:987654321098:function:my-function"
    }
  ]
}

```
Note that this policy can be viewed and edited directly in the AWS Lambda console under the 'Permissions' tab of your Lambda function.

**What is an IAM Role?**

An IAM role is an entity within AWS that defines a set of permissions that dictate what the identity can and cannot do in AWS. IAM roles can be assumed by trusted entities, such as IAM users, applications, or AWS services, including AWS Lambda. Roles are a secure way to grant permissions that applications can assume when they need to perform actions on your behalf.

**Example of an IAM Role Policy for Lambda:**

Consider an IAM role that grants permission to invoke any Lambda function in your account:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "*"
    }
  ]
}

```
You can create and manage IAM roles in the IAM console, under the 'Roles' section.

**Resource-Based Policy vs. IAM Roles: The Differences**

The key differences between the two are:

- **Attachment**: Resource-based policies are attached directly to a Lambda function, while IAM roles are standalone entities.
- **Management**: Resource-based policies are managed in the Lambda console, whereas IAM roles are managed in the IAM console.
- **Scalability**: Resource-based policies are less scalable due to their size limit. IAM roles are more scalable as they don't have this limitation.
- **Flexibility**: IAM roles are more flexible, as they can be assumed by many different accounts and services without modifying the policy on the resource itself.

**Best Practices and the AWS Well-Architected Framework**

According to AWS best practices and the Well-Architected Framework, the choice between using a Lambda resource-based policy and IAM roles largely depends on the scale of your operation and the need for flexibility.

For simple scenarios with a few resources, a resource-based policy is adequate and easier to manage. However, as your environment grows, IAM roles are recommended. They offer greater scalability and flexibility, which align with the AWS Well-Architected Framework's principle of granting least privilege—providing only the necessary permissions to perform a task.

IAM roles are particularly beneficial when dealing with:

- Cross-account access.
- Applications that run on Amazon EC2 or other AWS services that need to perform actions on your Lambda functions.
- Environments where functions are invoked by many different principals.

**Cross-Account Access via IAM Roles**

To enable cross-account access, you must create an IAM role with the necessary permissions and then allow other AWS accounts to assume that role. Here's how you can achieve this:

**Step 1: Create an IAM Role**

First, you create an IAM role in the account that owns the Lambda function. You define a trust policy that allows entities from the other account to assume the role.

Trust Policy for IAM Role (Trust Relationship):

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::OTHER_ACCOUNT_ID:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

```
**Step 2: Attach Permissions to the IAM Role**

Next, you attach a permissions policy to the IAM role that grants the lambda:InvokeFunction permission.

Permissions Policy for IAM Role:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME"
    }
  ]
}

```
Replace REGION, ACCOUNT_ID, and FUNCTION_NAME with your specific details.

**Step 3: Assume the IAM Role from the Other Account**

The entity in the other account must then use the AWS Security Token Service (STS) to assume the IAM role. Here's how you could do that programmatically also using AWS SDK for Python (Boto3).

Concluding the blog here, I would like to say while resource-based policies offer a quick and easy way to grant access to your Lambda functions, they come with limitations, especially concerning policy size and scalability. IAM roles, on the other hand, provide a more robust and flexible solution that can grow with your AWS environment.

When designing your cloud architecture, consider using IAM roles for their scalability and adherence to the principle of least privilege. By doing so, you'll ensure your AWS infrastructure remains secure, efficient, and well-aligned with AWS best practices.