Skip to content

Commit

Permalink
fix(apigateway): LambdaRestApi fails when a user defined Stage is att…
Browse files Browse the repository at this point in the history
…ached (#5838)

LambdaRestApi, by default, sets up a proxy integration as part of its
construction which in turn binds the specified lambda function handler
to the proxy using the LambdaIntegration class.

The LambdaIntegration class needs to set up the right IAM permissions
so API Gateway is able to invoke the Lambda function. The policy for
this permission requires the ARN of the 'ANY' Method that is set up by
the Proxy.

When the 'deploy' option is set, it indicates to the RestApi construct
and its sub-constructs (of which LambdaRestApi is one) to create a
default deployment and stage as part of its construction. The user can
also unset the 'deploy' option and specify their own Stage by setting
the 'deploymentStage' on the RestApi construct.

However, when the 'deploy' option is unset, the LambdaIntegration class
cannot compute the ARN for the 'ANY' Method since there's no Stage and
Deployment created. This generates at synthesis, even though there may
be a Stage that the user has configured against the RestApi later on.

The fix here is straightforward. Computation of the Method ARN should
occur at the time of synthesis rather than at the time of construction.

fixes #5744

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
nija-at and mergify[bot] committed Jan 17, 2020
1 parent 8a640df commit 05719d7
Show file tree
Hide file tree
Showing 3 changed files with 410 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts
@@ -1,5 +1,6 @@
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import { Lazy } from '@aws-cdk/core';
import { IntegrationOptions } from '../integration';
import { Method } from '../method';
import { AwsIntegration } from './aws';
Expand Down Expand Up @@ -60,7 +61,7 @@ export class LambdaIntegration extends AwsIntegration {
this.handler.addPermission(`ApiPermission.${desc}`, {
principal,
scope: method,
sourceArn: method.methodArn,
sourceArn: Lazy.stringValue({ produce: () => method.methodArn }),
});

// add permission to invoke from the console
Expand Down
@@ -0,0 +1,379 @@
{
"Resources": {
"myfnServiceRole7822DC24": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"myfn8C66D016": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"myfnServiceRole7822DC24",
"Arn"
]
},
"Runtime": "nodejs10.x"
},
"DependsOn": [
"myfnServiceRole7822DC24"
]
},
"lambdarestapiF559E4F2": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "lambdarestapi"
}
},
"lambdarestapiCloudWatchRoleA142878F": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
]
]
}
]
}
},
"lambdarestapiAccount856938D8": {
"Type": "AWS::ApiGateway::Account",
"Properties": {
"CloudWatchRoleArn": {
"Fn::GetAtt": [
"lambdarestapiCloudWatchRoleA142878F",
"Arn"
]
}
},
"DependsOn": [
"lambdarestapiF559E4F2"
]
},
"lambdarestapiproxyB0E963B7": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"lambdarestapiF559E4F2",
"RootResourceId"
]
},
"PathPart": "{proxy+}",
"RestApiId": {
"Ref": "lambdarestapiF559E4F2"
}
}
},
"lambdarestapiproxyANYApiPermissionLateBoundDeploymentStageStacklambdarestapiCE6017F6ANYproxy2C5460ED": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "lambdarestapiF559E4F2"
},
"/",
{
"Ref": "stage0661E4AC"
},
"/*/{proxy+}"
]
]
}
}
},
"lambdarestapiproxyANYApiPermissionTestLateBoundDeploymentStageStacklambdarestapiCE6017F6ANYproxyCC4F6BB2": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "lambdarestapiF559E4F2"
},
"/test-invoke-stage/*/{proxy+}"
]
]
}
}
},
"lambdarestapiproxyANYC900233F": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "ANY",
"ResourceId": {
"Ref": "lambdarestapiproxyB0E963B7"
},
"RestApiId": {
"Ref": "lambdarestapiF559E4F2"
},
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"/invocations"
]
]
}
}
}
},
"lambdarestapiANYApiPermissionLateBoundDeploymentStageStacklambdarestapiCE6017F6ANY35688E13": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "lambdarestapiF559E4F2"
},
"/",
{
"Ref": "stage0661E4AC"
},
"/*/"
]
]
}
}
},
"lambdarestapiANYApiPermissionTestLateBoundDeploymentStageStacklambdarestapiCE6017F6ANY239CFD70": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "lambdarestapiF559E4F2"
},
"/test-invoke-stage/*/"
]
]
}
}
},
"lambdarestapiANYB9BB3FB2": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "ANY",
"ResourceId": {
"Fn::GetAtt": [
"lambdarestapiF559E4F2",
"RootResourceId"
]
},
"RestApiId": {
"Ref": "lambdarestapiF559E4F2"
},
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"myfn8C66D016",
"Arn"
]
},
"/invocations"
]
]
}
}
}
},
"deployment33381975": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "lambdarestapiF559E4F2"
}
}
},
"stage0661E4AC": {
"Type": "AWS::ApiGateway::Stage",
"Properties": {
"RestApiId": {
"Ref": "lambdarestapiF559E4F2"
},
"DeploymentId": {
"Ref": "deployment33381975"
},
"StageName": "prod"
}
}
}
}

0 comments on commit 05719d7

Please sign in to comment.