Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws-lambda: Cannot grant url invoke by ArnPrincipal #31059

Closed
95Wictor opened this issue Aug 8, 2024 · 4 comments
Closed

aws-lambda: Cannot grant url invoke by ArnPrincipal #31059

95Wictor opened this issue Aug 8, 2024 · 4 comments
Assignees
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@95Wictor
Copy link

95Wictor commented Aug 8, 2024

Describe the bug

The CDK fails to synth if an ArnPrincipal is given to aws-lambda.Function.grantInvokeUrl.

Expected Behavior

grantInvokeUrl should accept ArnPrincipal, as grantInvoke does and as aws-s3.Bucket.grantRead does.

Current Behavior

En error occurs during synthesis: Resolution error: ID components may not include unresolved tokens: InvokeFunctionUrlArnPrincipal(${Token[TOKEN.59]}).

Reproduction Steps

Create a new CDK Typescript app, and replace the sample stack code with the following. Then run npx cdk synth.

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { ArnPrincipal, ServicePrincipal } from 'aws-cdk-lib/aws-iam';

export class ProductionStack extends cdk.Stack {
	constructor(scope: Construct, id: string, props?: cdk.StackProps) {
		super(scope, id, props);

		// These resources will grant permissions to a Lambda function
		const someBucket = new Bucket(this, 'someBucket', {
			removalPolicy: cdk.RemovalPolicy.DESTROY,
		});
		const lambdaThatWillGrant = new Function(this, 'someLambda', {
			runtime: Runtime.PYTHON_3_12,
			handler: 'handler',
			code: Code.fromInline('def handler(context):\n\treturn "hi"'),
		});
		lambdaThatWillGrant.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);

		// This lambda function will have permissions to use the above resources
		const lambdaThatWillInvoke = new Function(this, 'grantee', {
			runtime: Runtime.PYTHON_3_12,
			handler: 'handler',
			code: Code.fromInline('def handler(context):\n\treturn "hi, pretend I am invoking the other lambda or reading form S3"'),
		});
		lambdaThatWillInvoke.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);

		// Now we grant permissions.
		const arnPrincipal = new ArnPrincipal(lambdaThatWillInvoke.functionArn);
		someBucket.grantRead(arnPrincipal); //works
		// Below line does not work. Synth error: " Resolution error: ID components may not include unresolved tokens: InvokeFunctionUrlArnPrincipal(${Token[TOKEN.59]})."
		lambdaThatWillGrant.grantInvokeUrl(arnPrincipal);

		// To get around this issue, we can use a conditional principal
		const conditionalPrincipal = new ServicePrincipal('lambda.amazonaws.com').withConditions({
			// Creating the condition has its own problems, but these would be separate issues
			// 1) The AWS here MUST be lowercase, despite it showing uppercase in the AWS console.
			//    https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html (It should be case-insensitive.)
			// 2) We also cannot use StringEquals for Lambda, though we if the bucket was granting to this principal.
			"ArnLike": { "aws:SourceArn": lambdaThatWillInvoke.functionArn }
		});
		lambdaThatWillGrant.grantInvokeUrl(conditionalPrincipal); // works
	}
}

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.151.0 (build b8289e2)

Framework Version

No response

Node.js Version

20.9.0

OS

Windows 11

Language

TypeScript

Language Version

5.5.4

Other information

No response

@95Wictor 95Wictor added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Aug 8, 2024
@github-actions github-actions bot added the @aws-cdk/aws-lambda Related to AWS Lambda label Aug 8, 2024
@ashishdhingra ashishdhingra self-assigned this Aug 8, 2024
@ashishdhingra ashishdhingra added needs-reproduction This issue needs reproduction. p2 and removed needs-triage This issue or PR still needs to be triaged. labels Aug 8, 2024
@ashishdhingra
Copy link
Contributor

ashishdhingra commented Aug 8, 2024

@95Wictor Good afternoon. Thanks for opening the issue. I was able to reproduce the issue at my end getting error Error: Resolution error: ID components may not include unresolved tokens: InvokeFunctionUrlArnPrincipal(${Token[TOKEN.309]})..

Here are my findings for the root cause:

  • For lambda.grantInvokeUrl() scenario, the logic constructs an identifier via statement const identifier = `InvokeFunctionUrl${grantee.grantPrincipal}`; // calls the .toString() of the principal. As noted in the comment , it invokes toString() method of the principal. The identifier is used to maintain map Function URL invocation grants.

    • For ArnPrincipal, toString() is implemented like return `ArnPrincipal(${this.arn})`;. This relies on this.arn. For your use case, this.arn is the ARN of Lambda function which would invoke. The ARN is not yet resolved until the CDK stack is deployed. Hence, it is tokenized.
    • For ServicePrincipal, toString() is implemented like return `ServicePrincipal(${this.service})`;. This relies on the constant string this.service, which in your use case is lambda.amazonaws.com.

    Since, ARN for an ArnPrincipal is tokenized, we are getting the error.

  • For s3.grantRead(), it doesn't rely on generating identifier which might call toString() method of the underlying Principal. Hence ArnPrincipal works in this scenario.

The reason for using a map for lambda.grantInvokeUrl(), (per code comment) is to memoize the result so subsequent grantInvoke() calls are idempotent. Hence, ArnPrincipal would not work in this scenario.

Thanks,
Ashish

@ashishdhingra ashishdhingra added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. p3 and removed p2 needs-reproduction This issue needs reproduction. labels Aug 8, 2024
@95Wictor
Copy link
Author

Thanks for looking into it. I see you've added the "response-requested" label, but I don't see any questions in your comment. Do you need anything from me?

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Aug 10, 2024
@ashishdhingra
Copy link
Contributor

ashishdhingra commented Aug 10, 2024

Thanks for looking into it. I see you've added the "response-requested" label, but I don't see any questions in your comment. Do you need anything from me?

@95Wictor The response-requested label was added so that you could review the findings. Based on the findings, this is not a bug. Hence, closing this issue.

Thanks,
Ashish

@ashishdhingra ashishdhingra added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Aug 10, 2024
@ashishdhingra ashishdhingra closed this as not planned Won't fix, can't repro, duplicate, stale Aug 11, 2024
Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
Development

No branches or pull requests

2 participants