'Deploy AWS Lambda with function URL via Cloudformation

Since a few days, AWS Lambdas can be exposed as web services directly without an API Gateway.

This works fine when setting up through the UI console, but I can’t seem to get it done with Cloudformation, because the resource policy is not attached with AuthType: NONE. And without the policy, I get "message": "Forbidden" from AWS when trying to access the Lambda through the function url.

My Lambda is the following:

exports.handler = async event => {
    return {
        statusCode: 200,
        body: JSON.stringify("Hello World")
    }
}

and here’s the CFN template:

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  stackName:
    Type: String
  lambdaFile:
    Type: String
  lambdaBucket:
    Type: String

Resources:
  lambdaRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action:
              - "sts:AssumeRole"
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
      Policies:
        - PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Effect: "Allow"
                Resource:
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${stackName}:*"
          PolicyName: "lambda"

  runtimeLambdaFunction:
    Type: "AWS::Lambda::Function"
    Properties:
      Code:
        S3Bucket: !Ref lambdaBucket
        S3Key: !Ref lambdaFile
      Environment:
        Variables:
          NODE_ENV: production
      FunctionName: !Sub "${stackName}-runtime"
      Handler: runtime.handler
      MemorySize: 128
      Role: !GetAtt lambdaRole.Arn
      Runtime: "nodejs14.x"
      Timeout: 5

  lambdaLogGroup:
    Type: "AWS::Logs::LogGroup"
    Properties:
      LogGroupName: !Sub "/aws/${stackName}"
      RetentionInDays: 30

  runtimeLambdaUrl:
    Type: "AWS::Lambda::Url"
    Properties:
      AuthType: NONE
      TargetFunctionArn: !Ref runtimeLambdaFunction

Outputs:
  runtimeLambdaUrl:
    Value: !GetAtt runtimeLambdaUrl.FunctionUrl

The interesting thing is that I can add the policy through the UI console, and then it works.

Here’s the initial config screen for the function URL right after CFN deployment:

enter image description here

This is what I see when pushing the “Edit” button:

enter image description here

After clicking “Save”, I get the following (note the blue box):

enter image description here

Also, when I go into “Edit” mode again, I now see the following:

enter image description here

After that, the function can be accessed via its URL.

I tried to add the policy into my CFN stack, either standalone as AWS::IAM::Policy, but then it is not a resource-based policy or as an additional action on the lambdaRole. But in either case, I can’t add a Principal and the policy doesn’t have an effect.

Does anybody know how I can make a pure Clouformation deployment for a Lambda with a function URL? Or is this a bug in Cloudformation and/or Lambda?



Solution 1:[1]

Your template is missing AWS::Lambda::Permission, thus its does not work. You already know what the permissions should be based on AWS console inspection, so you have to recreate those permissions using AWS::Lambda::Permission. This allows you to specify FunctionUrlAuthType.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marcin