Skip to content

Missing lambda:InvokeFunction permission #29

Description

@fermarichal

After mu deploy, a Lambda Function URL created with AuthType=NONE returns 403 Forbidden / x-amzn-ErrorType: AccessDeniedException for every request, even though the auth type is NONE and the resource policy looks correct.

Root cause: since October 2025, new Lambda Function URLs require both lambda:InvokeFunctionUrl and lambda:InvokeFunction in the resource-based policy. mu only adds lambda:InvokeFunctionUrl, so the policy is incomplete and AWS denies the request.

From the AWS docs:

Starting in October 2025, new function URLs will require both lambda:InvokeFunctionUrl and lambda:InvokeFunction permissions.

If a function's resource-based policy doesn't grant lambda:InvokeFunctionUrl and lambda:InvokeFunction permissions, users will get a 403 Forbidden error code when they try to invoke your function URL. This will occur even if the function URL uses the NONE auth type.

Docs: https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html

Where it happens in mu

mu/libs/lamb.py, function_url() creates the URL config with AuthType='NONE' and then calls add_permission for only lambda:InvokeFunctionUrl:

self.lc.add_permission(
    FunctionName=func_arn,
    StatementId='AllowPublicAccessFunctionUrl',
    Action='lambda:InvokeFunctionUrl',
    Principal='*',
    FunctionUrlAuthType='NONE',
)

The second statement required by AWS (the lambda:InvokeFunction action, scoped to function-URL calls via lambda:InvokedViaFunctionUrl) is never added.

Reproduction

  1. mu provision <env> + mu deploy --build <env> for a function with a public (NONE) Function URL.
  2. curl https://<id>.lambda-url.<region>.on.aws/403, body {"Message":"Forbidden. For troubleshooting Function URL authorization issues..."}.
  3. aws lambda get-function-url-config shows AuthType: NONE; aws lambda get-policy shows only the lambda:InvokeFunctionUrl statement.

Workaround

Add the missing lambda:InvokeFunction statement manually after deploy (it persists across subsequent mu deploy runs; only needs re-adding if the function is deleted and recreated):

aws lambda add-permission \
  --function-name <function-name> \
  --statement-id FunctionURLInvokeAllowPublicAccess \
  --action lambda:InvokeFunction \
  --principal '*' \
  --invoked-via-function-url

Suggested fix

In function_url(), when creating a NONE Function URL, add the second permission statement alongside the existing one (mirrors what the Lambda console / AWS SAM now generate automatically):

self.lc.add_permission(
    FunctionName=func_arn,
    StatementId='FunctionURLInvokeAllowPublicAccess',
    Action='lambda:InvokeFunction',
    Principal='*',
    InvokedViaFunctionUrl=True,
)

(The same dual-permission requirement also applies to AuthType=AWS_IAM URLs.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions