npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

serverless-iam-test-helper

v1.0.1

Published

Helper for testing Lambda IAM Roles created by Serverless Framework.

Downloads

27

Readme

serverless-iam-test-helper

Helper that allows easy testing of AWS Lambda IAM roles that were created in Serverless Framework project using serverless-iam-roles-per-function plugin. Works with jest testing framework.

Compatibility with AWS SDK

The current version >= 1.0.0 of this library works with AWS SDK v3. For AWS SDK v2 compatibility use version 0.0.4.

How to use?

1. Install as a dev dependency

npm i -D serverless-iam-test-helper

2. Make sure there is a dedicated role per function

This library works with IAM role naming convention defined by serverless-iam-roles-per-function plugin. Make sure you're using it.

3. Write test in jest

In your jest test suite add a beforeAll method where you will assume the Lambda function's IAM Role by providing LAMBDA_LOGICAL_NAME as parameter.

import IamTestHelper from 'serverless-iam-test-helper';

describe('<LAMBDA_LOGICAL_NAME> Lambda IAM Role', () => {
  beforeAll(async () => {
    await IamTestHelper.assumeRoleByLambdaName('<LAMBDA_LOGICAL_NAME>')
  });

 // tests go here
})

Next, you implement the test.

  it('should ALLOW <an operation that should be allowed>', async () => {
    // GIVEN
    const payload = { ... }
    const service = new Service()

    // WHEN
    const actual = await service.operation(payload)

    // THEN
    expect(actual).toBe(...)
  })

The LAMBDA_LOGICAL_NAME is the same as defined in the serverless.yml in functions section. It is crucial to pass correct Lambda name to assumeRoleByLambdaName() method.

You may also test that Lambda's IAM Role will block not allowed operations. Here is a sample of such test.

  it('should DENY dynamodb:Query', async () => {
    // GIVEN
    const payload = { ... }
    const service = new MyEntityService()

    // WHEN
    let actual
    try {
      await service.getByQuery(payload)
    } catch (exception) {
      actual = exception
    }

    // THEN
    expect(actual.code).toBe('AccessDeniedException')
    expect(actual.message.includes('is not authorized to perform: dynamodb:Query')).toBeTruthy()
  })

In such test exception is expected 😉

How does it work?

The logic behind it is pretty simple. Instead of executing integration tests using your AWS profile (IAM user), which usually has admin privileges, and is defined in ~/.aws/credentials file.

I temporarily assume Lambda's IAM Role and execute the whole test suite within that role context. Any AWS SDK operation that your code wants to execute is checked by the IAM service. Depending on Lambda's IAM Role configuration it is allowed or denied.

Test suites run in an isolated fashion, that's why you may have multiple tests when each assumes other Lambda's role. After tests finish your own role (IAM user) is still present. This does not override any of your local settings nor environment variables.

You will get the best results when using that approach in projects that follow hexagonal architecture, so you can easily test in isolation parts (modules) of your application. Check out this serverless-hexagonal-template for Serverless Framework and an article describing why and how to use it.

Test compensation

The test compensation is an approach when test cleans up after itself. The IamTestHelper class provides a static method named leaveLambdaRole() and an alias assumeUserRoleBack(), which allows assuming your own (local IAM user) role back.

That proves to be useful when you test a Lambda IAM Role that is allowed only to create elements (i.e. in DynamoDB database) but you want to perform a cleanup of sorts after the test, so there aren't any leftovers after test execution.

My pattern to achieve that is depicted by code below:

import IamTestHelper from 'serverless-iam-test-helper';
// rest of imports

const cleanup = []

describe('<LAMBDA_LOGICAL_NAME> Lambda IAM Role', () => {
  
  beforeAll(async () => {
    await IamTestHelper.assumeRoleByLambdaName('<LAMBDA_LOGICAL_NAME>')
  });
 
 it('should ALLOW dynamodb:PutItem', async () => {
    // GIVEN
    const payload = { ... }
    const service = new MyEntityService()

    // WHEN
    const actual = await service.create(payload)

    // THEN
    expect(actual).toBe(...)

     // CLEANUP
    cleanup.push(actual)
  });

 afterAll(async () => {
    IamTestHelper.leaveLambdaRole()

    const userRoleAdapter = new DynamoDbAdapter()
    const deleteAll = cleanup.map((obj) => userRoleAdapter.delete({
      Key: obj.key(),
      TableName: process.env.tableName
    }))
    await Promise.all(deleteAll)
  });

})

This allows me to delete items that I have created during tests using my own IAM user profile with administrative privileges even when Lambda's IAM Role is not allowed to delete elements from DynamoDB table.

This helps me to keep my table in order.

Benefits

Using this approach has following advantages:

  • Better security due to tailored IAM Roles
  • Tests are executed locally against real services in the AWS cloud
  • Works in your CI/CD pipeline
  • Easier & faster development
  • Easier maintenance of the project: IAM Role tests protect against regression bugs in case of modification

Example

Working example is included in the serverless-hexagonal-template project. Follow instruction on its website to deploy your own project.

Sample jest tests that illustrate usage of that library are included in the serverless-hexagonal-template project.