问题
When using LambdaIntegration
class the bind function add permission to the lambda automatically:
bind(method) {
super.bind(method);
const principal = new iam.ServicePrincipal('apigateway.amazonaws.com');
const desc = `${method.restApi.node.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`;
this.handler.addPermission(`ApiPermission.${desc}`, {
principal,
scope: method,
sourceArn: method.methodArn,
});
// add permission to invoke from the console
if (this.enableTest) {
this.handler.addPermission(`ApiPermission.Test.${desc}`, {
principal,
scope: method,
sourceArn: method.testMethodArn,
});
}
}
Currently, I create multiple API Gateways who 90% of them trigger the same lambda function, this causes me the following error :
The final policy size (XXX) is bigger than the limit (20480)
More info here.
My goal is to override the bind function with my own function and handle the permissions by myself, something like that:
arn:aws:execute-api:{AWS_REGION}:{AWS_ACCOUNT}:{API_ID}/*/*/*
I know this is not a best practice but right now this is the only working workaround.
This is the new class I created :
class customLambdaIntegration extends apigateway.LambdaIntegration{
myHandler: lambda.IFunction;
constructor(handler: lambda.IFunction, options?: LambdaIntegrationOptions) {
super(handler, options);
this.myHandler = handler;
}
bind(method: Method) {
const principal = new iam.ServicePrincipal('apigateway.amazonaws.com');
const desc = `${method.restApi.node.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`;
this.myHandler.addPermission(`ApiPermission.${desc}`, {
principal,
scope: method,
sourceArn: method.methodArn.toString().replace(api.deploymentStage.stageName,'*')
});
}
}
Getting this error when running cdk list
:
if (!this.scope) { throw new Error('AwsIntegration must be used in API'); }
Problematic piece of code which throw the error:
class AwsIntegration extends integration_1.Integration {
constructor(props) {
const backend = props.subdomain ? `${props.subdomain}.${props.service}` : props.service;
const type = props.proxy ? integration_1.IntegrationType.AWS_PROXY : integration_1.IntegrationType.AWS;
const { apiType, apiValue } = util_1.parseAwsApiCall(props.path, props.action, props.actionParameters);
super({
type,
integrationHttpMethod: props.integrationHttpMethod || 'POST',
uri: cdk.Lazy.stringValue({ produce: () => {
if (!this.scope) {
throw new Error('AwsIntegration must be used in API');
}
return cdk.Stack.of(this.scope).formatArn({
service: 'apigateway',
account: backend,
resource: apiType,
sep: '/',
resourceName: apiValue,
});
} }),
options: props.options,
});
}
bind(method) {
this.scope = method;
}
}
LambdaIntegration documentation.
Any help will be much appreciated.
To whom this might be helpful, I open a feature request to implement my function and manually handle the lambda permission :
https://github.com/aws/aws-cdk/issues/5774
回答1:
Found the issue, this['scope'] = method;
were missing inside the bind function since AwsIntegration
class implements this.scope=method
.
Full code :
class customLambdaIntegration extends apigateway.LambdaIntegration{
// myScope : cdk.IConstruct;
myHandler: lambda.IFunction;
MyOptinos: apigateway.LambdaIntegrationOptions | undefined;
constructor(handler: lambda.IFunction, options?: LambdaIntegrationOptions) {
super(handler, options);
this.myHandler = handler;
this.MyOptinos = options;
}
bind(method: Method) {
this['scope'] = method;
const principal = new iam.ServicePrincipal('apigateway.amazonaws.com');
const desc = `${method.restApi.node.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`;
this.myHandler.addPermission(`ApiPermission.${desc}`, {
principal,
scope: method,
sourceArn: method.methodArn.toString().replace(api.deploymentStage.stageName,'*')
});
}
}
来源:https://stackoverflow.com/questions/59713522/cdk-override-bind-when-using-lambdaintegration