如何替换CfnInclude导入CloudFormation栈中的Lambda授权函数?
问题描述
我通过以下代码将CloudFormation模板导入AWS CDK:
const template = new include.CfnInclude(this, "Include", { templateFile: "../cloudformation-template/serverless.template.generated", parameters: {} });
导入的模板包含一个API Gateway REST API资源,该资源引用S3托管的Swagger文件。Swagger中定义了名为MyCustomAuthorizer的自定义授权器,其authorizerUri引用旧Lambda函数MyCustomAuthorizerLambda的ARN:
"securityDefinitions": { "MyCustomAuthorizer": { "type": "apiKey", "name": "Authorization", "in": "header", "x-amazon-apigateway-authtype": "custom", "x-amazon-apigateway-authorizer": { "authorizerUri": { "Fn::Join": [ "", [ "arn:aws:apigateway:", { "Ref": "AWS::Region" }, ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": ["MyCustomAuthorizerLambda", "Arn"] }, "/invocations" ] ] }, "authorizerResultTtlInSeconds": 300, "identitySource": "method.request.header.Authorization, context.path, context.httpMethod", "type": "request" } } }
Swagger中的API方法均通过security字段引用该授权器:
"/MyGETMethod.json": { "get": { "security": [{ "MyCustomAuthorizer": [] }], .... } }
我已通过CDK创建了新的Lambda函数:
var myNewAuthorizerLambda = new lambda.Function(this, 'MyNewAuthorizerLambda', { runtime: ..., code: lambda.Code.fromAsset(...), description: `An API Gateway Authorizer.`, handler: ... });
尝试过replaceDependency方法和遍历节点等方式,但未能将所有API方法的授权器引用从旧Lambda切换到新Lambda,请问该如何操作?此需求是否可行?
解决方案
完全可行,以下是两种可靠的实现方式:
方式一:直接修改导入的RestApi资源的Swagger定义
这种方式直接更新Swagger中的授权器配置,无需重新关联每个API方法:
- 获取导入的RestApi资源:
找到原CloudFormation模板中API Gateway资源的逻辑ID(比如MyRestApi),通过CfnInclude获取该资源:import * as apigateway from 'aws-cdk-lib/aws-apigateway'; const restApi = template.getResource("MyRestApi") as apigateway.CfnRestApi; - 更新Swagger中的授权器URI:
- 如果原RestApi的Swagger定义直接写在
body字段中:// 解析原Swagger JSON const swaggerContent = JSON.parse(restApi.body as string); // 替换授权器的Lambda ARN为新函数的ARN swaggerContent.securityDefinitions.MyCustomAuthorizer["x-amazon-apigateway-authorizer"].authorizerUri = `arn:aws:apigateway:${this.region}:lambda:path/2015-03-31/functions/${myNewAuthorizerLambda.functionArn}/invocations`; // 重新设置RestApi的body restApi.body = JSON.stringify(swaggerContent); - 如果原RestApi通过
s3Location引用S3托管的Swagger文件:
先将S3中的Swagger文件下载到本地,修改其中的authorizerUri为新Lambda的ARN,然后在CDK中读取修改后的本地文件并更新RestApi:import * as fs from 'fs'; // 读取本地修改后的Swagger文件 const modifiedSwagger = fs.readFileSync("../path/to/modified-swagger.json", "utf-8"); // 更新RestApi的body,同时移除S3Location引用 restApi.body = modifiedSwagger; restApi.s3Location = undefined;
- 如果原RestApi的Swagger定义直接写在
方式二:删除原授权器,重新创建并关联新授权器
这种方式适合需要完全替换授权器配置的场景:
- 移除原授权器的关联:
遍历栈中所有API方法资源,清除原授权器的引用:// 遍历当前栈的所有子节点,找到所有CfnMethod资源 this.node.children.forEach(child => { if (child instanceof apigateway.CfnMethod) { child.authorizerId = undefined; child.security = undefined; } }); - 创建新的自定义授权器:
使用CDK的L2构造创建符合原配置的新授权器:import { Duration } from 'aws-cdk-lib'; const newAuthorizer = new apigateway.RequestAuthorizer(this, "MyNewCustomAuthorizer", { handler: myNewAuthorizerLambda, identitySources: [ apigateway.IdentitySource.header("Authorization"), apigateway.IdentitySource.context("path"), apigateway.IdentitySource.context("httpMethod") ], resultsCacheTtl: Duration.seconds(300) }); - 关联新授权器到所有API方法:
找到所有API方法,设置授权类型和新授权器ID:// 假设已收集到所有CfnMethod实例(可通过遍历或getResource方法获取) const methods = [/* 所有API方法资源实例 */]; methods.forEach(method => { method.authorizationType = "CUSTOM"; method.authorizerId = newAuthorizer.authorizerId; });
注意事项
- 若不再需要旧Lambda函数
MyCustomAuthorizerLambda,可通过template.getResource("MyCustomAuthorizerLambda")获取后,调用node.remove()移除该资源,同时清理相关依赖。 - 操作完成后,使用
cdk diff查看变更,确认授权器的URI或关联的Lambda函数已更新为新资源。 - 确保新Lambda函数具备API Gateway调用它的权限(CDK的
RequestAuthorizer会自动创建该权限,手动关联时需额外配置)。
内容的提问来源于stack exchange,提问作者Elliveny
相关产品推荐
相关产品推荐

