-
Notifications
You must be signed in to change notification settings - Fork 4.5k
(appsync): Lambda authorizer permission is not scoped to appsync api arn #31550
Description
Describe the bug
When using a lambda authorizer with a GraphqlAPI, the cdk automatically creates the AWS::Lambda::Permission required for the AppSync API to invoke the lambda authorizer. It does not however add a SourceArn.
This conflicts with the control tower policy [CT.LAMBDA.PR.2], and it is in general good practice to scope permissions.
Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
I expected that the AWS::Lambda::Permission was scoped to only allow the "parent" AppSync API to invoke the authorizer.
Current Behavior
The CDK outputs a AWS:Lambda::Permission without a SourceArn property.
Reproduction Steps
- Add a graphql api
- Add a lambda function
- Set
defaultAuthorization(oradditionalAuthorizationTypesit doesn't matter) toaws_appsync.AuthorizationType.LAMBDAand point to the created lambda function - Inspect the created
AWS::Lambda::Permissionand notice thatSourceArnis missing.
const authorizer = new aws_lambda_nodejs.NodejsFunction(
this,
'authorizerLambda',
{},
);
new aws_appsync.GraphqlApi(this, 'api', {
name: 'api',
authorizationConfig: {
defaultAuthorization: {
authorizationType: aws_appsync.AuthorizationType.LAMBDA,
lambdaAuthorizerConfig: {
handler: authorizer,
},
},
},
});Possible Solution
Inspecting the aws_appsync package reveals that appsync adds this permission when discovering an authorizationType === AuthorizationType.LAMBDA.
The fix should be as simple as adding sourceArn: this.arn, but I don't have the time currently to setup local development and create a pull request.
Additional Information/Context
A workaround for now is to modify the permission with an Aspect:
export class AppsyncAuthorizerFixer implements IAspect {
appsyncArn: string;
constructor(appsyncArn: string) {
this.appsyncArn = appsyncArn;
}
public visit(node: IConstruct): void {
if (
node instanceof aws_lambda.CfnPermission &&
node.principal === 'appsync.amazonaws.com' &&
!node.sourceArn
) {
// The metadata is the only non-resolved value I could find that
// contains information about which lambda function the permission is tied to
const cdkPath = node.getMetadata('aws:cdk:path') as unknown;
if (!cdkPath) {
Annotations.of(node).addError('Permission metadata not present');
return;
}
if (
cdkPath.includes(`${idOfLambdaAuthorizer}/${idOfAppsyncApi}-appsync`)
) {
console.log(
`Found 'AWS::Lambda::Permission' for appsync authorizer with principal = 'appsync.amazonaws.com' and no sourceArn. Adding appsync arn...`,
cdkPath,
);
node.addPropertyOverride('SourceArn', this.appsyncArn);
}
}
}
}CDK CLI Version
2.159.1 (build c66f4e3)
Framework Version
No response
Node.js Version
v20.13.1
OS
MacOS 14.6.1 (Sonoma)
Language
TypeScript
Language Version
Typescript (5.6.2)
Other information
No response