Skip to content

(@aws_cdk/custom_resources): from_sdk_calls() attaches incorrect permissions for Lambda InvokeCommand #34183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task
nlocascio45 opened this issue Apr 17, 2025 · 1 comment
Labels
@aws-cdk/custom-resources Related to AWS CDK Custom Resources bug This issue is a bug. p2

Comments

@nlocascio45
Copy link

Describe the bug

I created an AwsCustomResource and called the Lambda service with the InvokeCommand action. When attaching a policy using AwsCustomResourcePolicy.from_sdk_calls(), it attached a policy with action lambda:Invoke, which is not a valid action, the correct action is lambda:InvokeFunction.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

I expected lambda:InvokeFunction to be attached to my custom resource function permission.

Current Behavior

lambda:Invoke was attached to my custom resource function permission.

Reproduction Steps

The following template should reproduce the issue once parameters are added:

from aws_cdk import custom_resources as cr
cr.AwsCustomResource(
  self,
  id='id',
  install_latest_aws_sdk=True,
  on_create=cr.AwsSdkCall(
    service='Lambda',
    action='InvokeCommand',
    parameters={
                    
    }
  ),
  policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
    resources=[cr.AwsCustomResourcePolicy.ANY_RESOURCE]
  )
)

Possible Solution

I took a quick look in the code and it appears that the logic to normalize an action name strips "Command" if necessary, but it does not account for the scenario where the command name is slightly different from the necessary permission, so this logic will likely need to be modified.

Additional Information/Context

The workaround is easy enough, we can just use AwsCustomResourcePolicy.from_statements() instead. However, I figured I would raise this in the event that this could impact other SDK calls.

CDK CLI Version

2.1007.0

Framework Version

No response

Node.js Version

v22.11.0

OS

macOS Sequoia 15.4

Language

Python

Language Version

Python 3.11.9

Other information

No response

@nlocascio45 nlocascio45 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Apr 17, 2025
@github-actions github-actions bot added the @aws-cdk/custom-resources Related to AWS CDK Custom Resources label Apr 17, 2025
@ykethan
Copy link
Contributor

ykethan commented Apr 17, 2025

Hey @nlocascio45, thank you for reporting this behavior. I was able to reproduce this issue using the following

import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as cr from "aws-cdk-lib/custom-resources";
import * as iam from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";

export class LambdaInvokeStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create a simple Lambda function to invoke
    const targetFunction = new lambda.Function(this, "TargetFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "index.handler",
      code: lambda.Code.fromInline(`
        exports.handler = async () => {
          return {
            statusCode: 200,
            body: 'Hello from Lambda!'
          };
        };
      `),
    });

    const customResource = new cr.AwsCustomResource(this, "LambdaInvoker", {
      onCreate: {
        service: "Lambda",
        action: "invoke",
        parameters: {
          FunctionName: targetFunction.functionName,
          Payload: JSON.stringify({ message: "Hello" }),
        },
        physicalResourceId: cr.PhysicalResourceId.of("LambdaInvokerResource"),
      },
    });
  }
}

on synth this generated a policy statement as

  Properties:
      PolicyDocument:
        Statement:
          - Action: lambda:Invoke
            Effect: Allow

This currently occurs as the normalizeActionName function

/**
* Normalize an action name from:
*
* - camelCase SDKv2 method name
* - PascalCase API name
* - SDKv3 command class name
*
* To a PascalCase API name.
*/
function normalizeActionName(v3Service: string, action: string) {
if (action.charAt(0).toLowerCase() === action.charAt(0)) {
return action.charAt(0).toUpperCase() + action.slice(1);
}
// If the given word is in the APIs ending in 'Command' for this service,
// return as is. Otherwise, return with a potential 'Command' suffix stripped.
if (v3Metadata()[v3Service]?.commands?.includes(action)) {
return action;
}
return action.replace(/Command$/, '');
}

which currently only strip the command suffix

As a workaround, you can utilize the AwsCustomResourcePolicy.fromStatements to add explicit policy statements.

import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as cr from "aws-cdk-lib/custom-resources";
import { Construct } from "constructs";

export class LambdaInvokeStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create a simple Lambda function to invoke
    const targetFunction = new lambda.Function(this, "TargetFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "index.handler",
      code: lambda.Code.fromInline(`
        exports.handler = async () => {
          return {
            statusCode: 200,
            body: 'Hello from Lambda!'
          };
        };
      `),
    });

    // Create custom resource that will try to invoke the Lambda
    const customResource = new cr.AwsCustomResource(this, "LambdaInvoker", {
      onCreate: {
        service: "Lambda",
        action: "invoke",
        parameters: {
          FunctionName: targetFunction.functionName,
          Payload: JSON.stringify({ message: "Hello" }),
        },
        physicalResourceId: cr.PhysicalResourceId.of("LambdaInvokerResource"),
      },

      policy: cr.AwsCustomResourcePolicy.fromStatements([
        new iam.PolicyStatement({
          actions: ["lambda:InvokeFunction"],
          resources: [targetFunction.functionArn],
        }),
      ]),
    });
  }
}

@ykethan ykethan added p2 and removed needs-triage This issue or PR still needs to be triaged. labels Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/custom-resources Related to AWS CDK Custom Resources bug This issue is a bug. p2
Projects
None yet
Development

No branches or pull requests

2 participants