🕶️

Lambda Function URLsをCloudFormationとCDKでデプロイする

2022/09/19に公開

やったこと

  • Lambda関数URLsをCfnでデプロイ
  • Lambda関数URLsをCDKでデプロイ

やってないこと

  • Lambda関数URLsでできること/できないことを試したりは、していません

Lambda Function URLsとは

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

CloudFormation

ymlファイル

lambda_function_url_demo.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Lambda Function Url sample"

Resources:
  LambdaTestFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile:
          Fn::Sub: |
            exports.handler = async (event, context) => {
              console.log('Event= ' + JSON.stringify(event));
              const query_string = event.rawQueryString;
              const response = {

                statusCode: 200,
                body: JSON.stringify({
                  hello: 'Hello from Lambda Function Urls!',
                  message: query_string
                })
              };

              return response;
            };
      Description: Lambda function return message
      FunctionName: LambdaFunctionUrlsTest
      Handler: index.handler
      Role: !GetAtt "LambdaFunctionUrlIAMRole.Arn"
      Runtime: nodejs16.x

  LambdaTestFunctionUrl:
    Type: AWS::Lambda::Url
    Properties:
      AuthType: NONE
      TargetFunctionArn: !Ref LambdaTestFunction

  permissionForURLInvoke:
     Type: AWS::Lambda::Permission
     Properties:
       FunctionName: !Ref LambdaTestFunction
       FunctionUrlAuthType: 'NONE'
       Action: lambda:InvokeFunctionUrl
       Principal: '*'

  LambdaFunctionUrlIAMRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action:
              - "sts:AssumeRole"
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
      Policies:
        - PolicyName: CloudWatchLogsPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "logs:*"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"

使い方

  • 上記を保存してCloudFormationでデプロイしてくだい
  • 作られたLambda関数のページで、Function URLを調べます

  • ``https://abcdefg.lambda-url.us-east-1.on.aws/?message=HelloWorld`という風にしてブラウザで開きます。こんな風に表示されるはずです。
{"hello":"Hello from Lambda Function Urls!","message":"message=HelloWorld"}

メモなど

  • LambdaのCfnから、Type: AWS::Lambda::UrlType: AWS::Lambda::Permission(リソースポリシー)を追加すればよい
  • permissionForURLInvokeFunctionUrlAuthType: 'NONE'を書き忘れてデプロイしたら、This policy could enable public access to your lambda function as it allows all Principals (*) to perform lambda:InvokeFunctionUrl action. You must specify lambda:FunctionUrlAuthType condition if intend to enable public access というエラー。この公式docのPublic Function URL Invokeのところにきちんと書いてありました。
  • GETでの呼び出しのパラメータとしてhttps://abcdefg.lambda-url.us-east-1.on.aws/?message=HelloWorldということが紹介されていますが、event.rawQueryStringがそのままmessage=HelloWorldとして返ります。(message=はなくてもいいかも)
  • TODO:アクセスをPublicにしていて、URLが漏れてDoS攻撃を受けたらどうなるのかが気になる。

CDK

minimum working example

lib/lambda-urls.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

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

    const fn = new lambda.Function(this, 'HelloLambdaHandler', {
      runtime: lambda.Runtime.PYTHON_3_9,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'my_lambda.handler',
    });

    const fnUrl = fn.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    });
  }
}
lambda/my_lambda.py
import json


def handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

使い方

  • cdk init app --language=typescriptでスタートして、上記2ファイルだけ変えています
  • CDKだと、addFunctionUrlするときにPermissionも自動で設定してくれて便利です。

まとめ感想

  • AWS Lambda Function URLsを実装したかったので、CloudFormationとCDKでやってみました
  • やっぱりCDKが便利

注意

  • リソースの削除をお忘れなく

Discussion