Custom Resources Lambda using deploymentRole?

Hello,

I’m running into an issue: I want to control the rights given to CloudFormation when it comes to deploying a Serverless API. So, I create a role with just the required permissions and add this to the serverless.yml:

iam:
deploymentRole: arn:aws:iam::${aws:accountId}:role/cloudformation-serverless-execution-role

When I run this, execution fails with the following message:

An error occurred: CustomDashresourceDashapigwDashcwDashroleLambdaFunction - Resource handler returned message: "The role defined for the function cannot be assumed by Lambda.

This confused me for a while as I failed to understand how a role applied to CloudFormation could give me that error. Things got even more confusing when I simply removed the deploymentRole from serverless.yml after which everything worked perfectly (with the role still being used by CloudFormation as the stack already existed and so the IAM role remained in place).

I eventually looked into the serverless-state.json where I found this:

“CustomDashresourceDashapigwDashcwDashroleLambdaFunction”: {
“Type”: “AWS::Lambda::Function”,
“Properties”: {
“Code”: {
“S3Bucket”: {
“Ref”: “ServerlessDeploymentBucket”
},
“S3Key”: “serverless/demo-api/dev/1633590891473-2021-10-07T07:14:51.473Z/custom-resources.zip”
},
“FunctionName”: “demo-api-dev-custom-resource-apigw-cw-role”,
“Handler”: “apiGatewayCloudWatchRole/handler.handler”,
“MemorySize”: 1024,
“Runtime”: “nodejs12.x”,
“Timeout”: 180,
“Role”: “arn:aws:iam::XXXXXXXXXXXX:role/cloudformation-serverless-execution-role”
},

Why is the deploymentRole being applied to a Lambda function while the Serverless.yml reference page clearly states that this role is used for CloudFormation?

Seems like a bug to me because when not using the deploymentRole, a custom resources Lambda execution role gets generated that, as expected, has a very different policy than the policy I created for CloudFormation.

Just a guess, but the deployerRole is probably assumed by Cloudfront to deploy the actual resources, only after the Cloudformation template has been synthesised using the role/profile that the serverless cli is running under.

The deploymentRole is indeed assumed by CloudFront to deploy the actual resources. That is also what I want so no problem there.

The problem is: why is a role created for CloudFront being applied to a Lambda function (that as I understand it is being auto-generated for the Dashboard functionality which I don’t even use)?

If deploymentRole is present, it should only be applied to CloudFront and not to some auto-generated Lambda. When not using deploymentRole another role is generated for that Lambda which is also what should continue to happen when deploymentRole is being used as that auto-generated role works just fine.

Hi were you able to find a resolution to this issue? Currently running into the exact same issue and not sure what to do.

I was able to fix this issue for my setup.

Find out what role your CustomDashresourceDashapigwDashcwDashroleLambdaFunction uses with provider.iam.deploymentRole turned off/disabled.

Copy that role info from serverless-state.json and convert it to YAML with https://json2yaml.com/

Add the new role to your resources section in serverless.yml.

Example:

IamRoleCustomResourcesLambdaExecution:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: ‘2012-10-17’
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName:
Fn::Join:
- “-”
- - ${self:custom.stage}
- myproject
- custom-resources-lambda
PolicyDocument:
Version: ‘2012-10-17’
Statement:
- Effect: Allow
Resource:

Then add an extensions section to the end of your resources section to overwrite the deploymentRole on the CustomDashresource… resources.

extensions:
CustomDashresourceDashapigwDashcwDashroleLambdaFunction:
Properties:
Role:
Fn::GetAtt:
- IamRoleCustomResourcesLambdaExecution
- Arn

Re-enable provider.iam.deploymentRole and sls deploy…

Worked for me.

To use a custom resource, you’ll need to do three things:

  1. Write the logic for your custom resource;
  2. Make your custom resource login available by deploying to an AWS Lambda function or by subscribing to an SNS topic.
  3. Use the custom resource in your Formation template that references the Lambda function or SNS topic