Skip to content
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

Creating an API Gateway endpoint with a stage variable using a Lambda.Function.lambda_from_arn in AWS CDK doesn't work #30098

Open
InTomas98 opened this issue May 7, 2024 · 4 comments
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@InTomas98
Copy link

Describe the bug

When using Lambda.Function.function_from_arn() to get an AWS Lambda that was created from a previously created stack, so that in another stack to create an AWS ApiGateway resource referencing to the stage variable does not work.

When I'm doing this, without specifying a stage variable, everything works without any problem.was created

Expected Behavior

The API Gateway resource Lambda integration, with a stage variable, is to be created, because that is what happens when I create the AWS Lambda and use it to create an API Gateway resource in the same stack.an

Current Behavior

This works

TestLambda = lambda_.Function(
    self,
    "my_lambda",
    function_name="TestLambda",
    description="A Lambda to test permissions",
    code=lambda_code,
    memory_size=512,
    handler="my_lambda.main",
    runtime=lambda_.Runtime.PYTHON_3_9,
    timeout=Duration.minutes(1),
)

#get_gateway() is custom code to the the API

api = get_gateway(self.scope, gateway_name)
root = api.root

lambdaArn = TestLambda.function_arn + ":${stageVariables.lambdaAlias}"
integration = aws_apigateway.LambdaIntegration(lambdaArn)

endpoint = root.resource_for_path("/test_lambda_api/").add_method("GET", integration)

Reproduction Steps

This doesn't work

other_stack_lambda_arn_ = f"arn:aws:lambda:{self.region}:{self.account_id}:function:OtherStackLambd"
OtherStackLambda=  aws_lambda.Function.from_function_arn(self.scope, id=f"Role{lambda_arn_}", function_arn = other_stack_lambda_arn_ )

#get_gateway() is custom code to the the API

api = get_gateway(self.scope, gateway_name)
root = api.root

other_lambdaArn = OtherStackLambda.function_arn + ":${stageVariables.lambdaAlias}"
other_integration = aws_apigateway.LambdaIntegration(other_lambdaArn)

endpoint = root.resource_for_path("/test_lambda_api/other_lambda").add_method("GET", other_integration )

And I get the following error: [#/FunctionName: string [arn:aws:lambda:eu-west-1:668526471736:function:OtherStackLambd:${stageVariables.lambdaAlias}] does not match pattern ^(arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$], when I was expecting for this to create the endpoint like in the other case.

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.54.0

Framework Version

V1

Node.js Version

v14.20.0

OS

Linux

Language

Python

Language Version

Python 3.9.13

Other information

No response

@InTomas98 InTomas98 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels May 7, 2024
@github-actions github-actions bot added the @aws-cdk/aws-lambda Related to AWS Lambda label May 7, 2024
@pahud
Copy link
Contributor

pahud commented May 8, 2024

This looks like an error from CFN.

Can you run npx cdk synth and check the FunctionName prop of the two stacks and see if there's any difference?

@pahud pahud added p2 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. effort/medium Medium work item – several days of effort and removed needs-triage This issue or PR still needs to be triaged. labels May 8, 2024
@InTomas98
Copy link
Author

There is a difference. When the API Gateway resource is created from a Lambda that was created in that stack, the FucntionName looks like this:


    "FunctionName": {
     "Fn::GetAtt": [
      "LambdaTestLambda0C685943",
      "Arn"
     ]

But when I get a Lambda using Function.lambda_from_arn, to then create the resource in another stack, the FunctionName looks like this:


   "Type": "AWS::Lambda::Permission",
   "Properties": {
    "Action": "lambda:InvokeFunction",
    "FunctionName": "arn:aws:lambda:eu-west-1:444444444444:function:TestLambda",

In the case above it works, but when I define a stage variable, it looks like this, and the error occurs:

   "Type": "AWS::Lambda::Permission",
   "Properties": {
    "Action": "lambda:InvokeFunction",
    "FunctionName": "arn:aws:lambda:eu-west-1:444444444444:function:TestLambda:${stageVariables.lambdaAlias}",

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label May 8, 2024
@InTomas98
Copy link
Author

InTomas98 commented May 10, 2024

UPDATE: Got it working, and now the CDK is behaving like we were expecting, what we do is the following:

So everything works, but I'm doing something the documentation directly tells me isn't recommended

TestLambda = lambda_.Function(
    self,
    "my_lambda",
    function_name="TestLambda",
    description="A Lambda to test permissions",
    code=lambda_code,
    memory_size=512,
    handler="my_lambda.main",
    runtime=lambda_.Runtime.PYTHON_3_9,
    timeout=Duration.minutes(1),
)
#get_gateway() is custom code to the the API

api = get_gateway(self.scope, gateway_name)
root = api.root

lambdaArn = TestLambda.function_arn + ":${stageVariables.lambdaAlias}"
lambda_function =aws_lambda.Function.from_function_arn(self.scope,f'lambda_integration_request_{lambdaArn}' ,lambdaArn)
integration = aws_apigateway.LambdaIntegration(lambda_function, allow_test_invoke=False)

endpoint = root.resource_for_path("/test_lambda_api/").add_method("GET", integration)

But for the case where I'm trying to use a Lambda that was created from another stack to create a API Gateway resource, I'm doing it like this

# The Lambda name in this case is OtherStackLambd
other_stack_lambda_arn_ = f"arn:aws:lambda:{self.region}:{self.account_id}:function:OtherStackLambd"

#get_gateway() is custom code to the the API

api = get_gateway(self.scope, gateway_name)
root = api.root

other_lambdaArn = OtherStackLambda.function_arn + ":${stageVariables.lambdaAlias}"
integration = aws_apigateway.AwsIntegration(
          service='lambda',
          path=f'2015-03-31/functions/{lambdaArn}/invocations',
          region=self.region,
          proxy=True,
         options=aws_apigateway.LambdaIntegrationOptions(allow_test_invoke=False)                     
)
endpoint = root.resource_for_path("/test_lambda_api/other_lambda").add_method("GET", other_integration )

And doing this works, everything works fine. BUT I'm not gonna close this issue, because in the CDK documentation, it specifically says that AwsIntegration is intended for calling all AWS service actions, but is not recommended for calling a Lambda function, because the Lambda custom integration is a legacy technology.

So everything works, but I'm doing something the documentation directly tells me isn't recommended

@isiosis
Copy link

isiosis commented Aug 16, 2024

An alternative solution I used is to change the Integration.uri once the method has been integrated with the lambda integration using the cfnMethod.addPropertyOverride

const api = new apigateway.RestAPI() // define stage variables as necessary when created the stages
const sampleResource = api.root.addResource("sample");

const lambdaArn = "{your lambda arn}"

const lambdaIntegration = new apigateway.LambdaIntegration(
		lambda.Function.fromFunctionArn(
			this,
			"FunctionFromArn",
			lambdaArn
		),
		{
			proxy: false,
			integrationResponses: [
				{
				statusCode: "200",
				responseParameters: commonResponseParameters,
				},
                         ],
		}
	);

const sampleMethod = sampleResource.addMethod("GET", lambdaIntegration, {responses})

// This is the part that introduces the fix

// Override the integration URI to include the stage variable
const cfnMethod = sampleMethod.node.defaultChild as apigateway.CfnMethod;

cfnMethod.addPropertyOverride("Integration.Uri", {
			"Fn::Sub": [
				"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${yourArn}:${stage}/invocations",
				{
					yourArn: lambdaArn,
					stage: "${stageVariables.stage}", // my stage variable is called stage
				},
			],
		});

This will replace the invocation URI integrating the stagevariable as an alias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. effort/medium Medium work item – several days of effort p2
Projects
None yet
Development

No branches or pull requests

3 participants