Open lyenliang opened 4 years ago
Any update on this issue? We are currently blocked with this and would like to know if there are any alternative approach?
We are blocked with this issue, it is affecting our optimal design decision and forcing us to go for multiple API gateways. Our use case is: 1) Trying to deploy multiple stages for an API through CDK 2) Have one API gateway and multiples stages with stage variables (For example dev, test, and stage) 3) In the Method Integration Request part, we need to have the feasibility to pass stage variables to the Lambda function in the API gateway.
Please let us know what is the ETA?
Agree with rampatina - the inability to pass stage variables negates the ability to utilize API-GW stages as they were designed/intended to be used, forcing sub-optimal design of multiple GWs; one per stage.
Can someone point me to API Gateway;s documentation that allows this? Unfortunately, I'm not able to locate one easily enough.
I can't also find any direction on how to configure this on the uri parameter via the API or the CloudFormation parameter. The Uri
property of the CloudFormation resource type AWS::ApiGateway::Method
is where we specify the URI of the lambda function, in the case of lambda proxy integration.
Here is the docs from API gateway: https://docs.aws.amazon.com/apigateway/latest/developerguide/stage-variables.html Another reference link for sample use-case: https://aws.amazon.com/blogs/compute/using-api-gateway-stage-variables-to-manage-lambda-functions/
Now, the same configuration is not available in CDK.
Thanks for the links to the documentation. It's not clear right away from these how to set these up with CloudFormation, but I would hazard a guess that it should be added as part of the Uri
property of AWS::ApiGateway::Method
resource type.
Currently, we don't support this as part of the higher level constructs in the cdk. Recording as a feature request here.
You could work around this by using CDK's escape hatches and setting the Uri
property mentioned above.
Thanks.
I had the same issue and managed to get it working using the base Integration construct. Unfortunately I'm working with Typescript so not sure if this will translate over to CDK Python (I imagine it would though).
let integration = new apigateway.Integration({
type: apigateway.IntegrationType.AWS_PROXY,
integrationHttpMethod: 'POST',
uri: arn:aws:apigateway:<aws_region>:lambda:path/2015-03-31/functions/arn:aws:lambda:<aws_region>:<aws_account>:function:${stageVariables.stageFunction}/invocations',
});
Given lambdaRestApi is a convinience class, you'll have to do additional work setting up a RestAPI, stages, methods etc to get this running. But it is possible to achieve defining the Lambda function via stage variables using the above integration construct.
Hope it helps.
has there been any progress on this? trying to do the same using the java cdk
So the trick I've been using is Function.fromFunctionArn
with the regular function Arn plus the stageVariables
path. When doing this we cannot use LambdaIntegration
directly because CDK will try to add a IAM permission to that Arn automatically, and that will not be a valid permission Arn. So we need to manage the permissions ourselves, as shown below.
// Your regular lambda function
const func: lambda.Function = ...
// Create a Lambda with the dynamic stageVariables path
const stageLambda = lambda.Function.fromFunctionArn(
this,
`${func.functionName}-lambda-stage`,
`${func.functionArn}:\${stageVariables.environment}`
)
const credentialsRole = new iam.Role(this, 'apigateway-api-role', {
assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
})
// Add the regular lambda Arns to the credentialsRole
credentialsRole.addToPolicy(
new PolicyStatement({
actions: ['lambda:InvokeFunction'],
resources: [func.functionArn, `${func.functionArn}:*`],
effect: Effect.ALLOW,
})
)
// Add the stageLambda Arn to the integration.
const integration = new apigateway.AwsIntegration({
proxy: true,
service: 'lambda',
path: `2015-03-31/functions/${stageLambda.functionArn}/invocations`,
options: {
credentialsRole,
/* Additional options here */
},
})
I took a similar approach:
public class MultiLambdaIntegration extends Integration {
public MultiLambdaIntegration(Stack stack, String lambdaNameRoot) {
super(IntegrationProps.builder().integrationHttpMethod("POST")
.type(IntegrationType.AWS_PROXY)
.uri(String.format("arn:aws:apigateway:%s:lambda:path/2015-03-31/functions/arn:aws:lambda:%s:%s:function:%s-${stageVariables.lambdaEnv}/invocations", stack.getRegion(), stack.getRegion(), stack.getAccount(), lambdaNameRoot))
.build());
}
}
Whilst adding permission to the lambda:
.addPermission(
String.format("allow-api-lambda-invocation-%s-%s", lambdaNameRoot, environments[i]),
Permission.builder()
.action("lambda:InvokeFunction")
.principal(
ServicePrincipal.Builder.create("apigateway.amazonaws.com").build())
.sourceArn(api.getApi().arnForExecuteApi())
.build());
my god, thank you @thovden
So the trick I've been using is
Function.fromFunctionArn
with the regular function Arn plus thestageVariables
path. When doing this we cannot useLambdaIntegration
directly because CDK will try to add a IAM permission to that Arn automatically, and that will not be a valid permission Arn. So we need to manage the permissions ourselves, as shown below.// Your regular lambda function const func: lambda.Function = ... // Create a Lambda with the dynamic stageVariables path const stageLambda = lambda.Function.fromFunctionArn( this, `${func.functionName}-lambda-stage`, `${func.functionArn}:\${stageVariables.environment}` ) const credentialsRole = new iam.Role(this, 'apigateway-api-role', { assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), }) // Add the regular lambda Arns to the credentialsRole credentialsRole.addToPolicy( new PolicyStatement({ actions: ['lambda:InvokeFunction'], resources: [func.functionArn, `${func.functionArn}:*`], effect: Effect.ALLOW, }) ) // Add the stageLambda Arn to the integration. const integration = new apigateway.AwsIntegration({ proxy: true, service: 'lambda', path: `2015-03-31/functions/${stageLambda.functionArn}/invocations`, options: { credentialsRole, /* Additional options here */ }, })
any updates ?
Any updates ? Is so rare use-case ? Why AWS does not address this issue, after more than 4 years ?
Does anyone have any updates regarding this issue?
I was trying to achieve same thing using apigatewayv2. Following some of the approaches above, I was able to get it working. My use-case was -
Below is what I got working. It deploys , creates two aliases. You may use this for reference.
let exampleLambda = new lambdanodejs.NodejsFunction(this, "exampleLambda", {
functionName: `exampleLambda`,
runtime: Runtime,
timeout: cdk.Duration.seconds(30),
memorySize: 256,
entry: "lambda/exampleLambda/index.ts",
handler: "handler",
environment: {
AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1",
REGION: AWS_REGION,
},
bundling: {
nodeModules: [],
externalModules: [],
},
layers: [],
});
const exampleLambdadevalias = new lambda.Alias(this, "exampleLambda-dev-alias", {
aliasName: "dev",
version: exampleLambda.latestVersion,
});
const exampleLambdaprodalias = new lambda.Alias(this, "exampleLambda-prod-alias", {
aliasName: "prod",
version: exampleLambda.currentVersion,
});
const stageLambda = lambda.Function.fromFunctionArn(
this,
`${exampleLambda.functionName}-lambda-stage`,
`${exampleLambda.functionArn}:\${stageVariables.lambdaAlias}`
);
//create new http api
let exampleApi = new apigwv2.HttpApi(this, `example-api`, {
description: `example api`,
apiName: `example-api`,
corsPreflight: {
allowHeaders: ["*"],
allowMethods: [
apigwv2.CorsHttpMethod.OPTIONS,
apigwv2.CorsHttpMethod.POST,
apigwv2.CorsHttpMethod.PUT,
apigwv2.CorsHttpMethod.GET,
apigwv2.CorsHttpMethod.DELETE,
apigwv2.CorsHttpMethod.PATCH,
],
allowOrigins: ["*"],
allowCredentials: false,
},
});
//enable access log
exampleApi.addRoutes({
path: "/todo",
methods: [apigwv2.HttpMethod.GET],
integration: new HttpLambdaIntegration("example-lambda-integ", stageLambda),
});
const devStage = new apigwv2.CfnStage(this, "DevStage", {
apiId: exampleApi.httpApiId,
stageName: "dev",
autoDeploy: true,
stageVariables: {
lambdaAlias: "dev",
},
});
const prodStage = new apigwv2.CfnStage(this, "ProdStage", {
apiId: exampleApi.httpApiId,
stageName: "prod",
autoDeploy: true,
stageVariables: {
lambdaAlias: "prod",
},
});
exampleLambdadevalias.addPermission("AllowApiGatewayInvoke", {
principal: new iam.ServicePrincipal("apigateway.amazonaws.com"),
action: "lambda:InvokeFunction",
sourceArn: `arn:aws:execute-api:${AWS_REGION}:${AWS_ACCOUNT}:${exampleApi.httpApiId}/dev/*`,
});
exampleLambdaprodalias.addPermission("AllowApiGatewayInvoke", {
principal: new iam.ServicePrincipal("apigateway.amazonaws.com"),
action: "lambda:InvokeFunction",
sourceArn: `arn:aws:execute-api:${AWS_REGION}:${AWS_ACCOUNT}:${exampleApi.httpApiId}/prod/*`,
});
But I moved away from this approach in the end for few reasons.
:question: General Issue
How to pass a stage variable to lambda function field in API Gateway?
I have an API Gateway that triggers a lambda function specified by a stage variable
stageVariables.lbfunc
.How can I create this API Gateway with AWS CDK?
It looks like that I should create a special
handler
for LambdaRestApi.But I can't find any example code for doing this.
The following is my current code. I wish that
LambdaIntegration
's handler can be determined by a stage variable.Environment
Other information