はじめに
Lambdaを、API Gatewayを用いずに、URLで実行できる機能があります。
これをCloudFormation(とSAM)、CDKで作るサンプルをまとめてみました。
認証タイプは2つありますが、今回は「NONE」の例だけです。
参考
CloudFormation
昔書いた以下のテンプレートを用います。
最後に以下を加えただけです。
- AWS::Lambda::Url
- AWS::Lambda::Permission
- 出力
- スタックからURLがわかるようにするためだけ
- Lambda関数のプロパティから確認可能
AWSTemplateFormatVersion: 2010-09-09
Parameters:
LambdaFunctionName:
Type: String
Default: function-https
Resources:
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${LambdaFunctionName}"
RetentionInDays: 3653 # 未指定時は「失効しない」
FunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "for-lambdafunction-${LambdaFunctionName}"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: '/service-role/'
Policies:
# CloudWatch
- PolicyName: write-cloudwatchlogs
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*"
TargetFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Ref LambdaFunctionName
Role: !GetAtt FunctionRole.Arn
Runtime: python3.9
Handler: index.lambda_handler
Code:
ZipFile: !Sub |
def lambda_handler(event, context):
return 'hello, from function 1.'
##################################################
# 以下、URLと許可
##################################################
TargetFunctionUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: NONE
TargetFunctionArn: !GetAtt TargetFunction.Arn
TargetFunctionUrlPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunctionUrl
FunctionName: !GetAtt TargetFunction.Arn
FunctionUrlAuthType: NONE
Principal: "*"
Outputs:
FunctionUrl:
Value: !GetAtt TargetFunctionUrl.FunctionUrl
Export:
Name: TargetFunctionUrl
SAM
こちらも、昔のコードを流用します。
先ほどと同じものを追加するだけです。
template..yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Lambda Function
Parameters:
LambdaFunctionName:
Type: String
Default: "testfunction001"
Resources:
FunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "for-lambdafunction-${LambdaFunctionName}"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: '/service-role/'
Policies:
# CloudWatch
- PolicyName: write-cloudwatchlogs
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*"
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${LambdaFunctionName}
RetentionInDays: 3653
TargetFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref LambdaFunctionName
Role: !GetAtt FunctionRole.Arn
CodeUri: functions/
Handler: app.lambda_handler
Runtime: python3.9
##################################################
# 以下、URLと許可
##################################################
TargetFunctionUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: NONE
TargetFunctionArn: !GetAtt TargetFunction.Arn
TargetFunctionUrlPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunctionUrl
FunctionName: !GetAtt TargetFunction.Arn
FunctionUrlAuthType: NONE
Principal: "*"
Outputs:
FunctionUrl:
Value: !GetAtt TargetFunctionUrl.FunctionUrl
Export:
Name: TargetFunctionUrl
CDK
CDKで記述すると以下のようになります。CFnテンプレートと比べてとてもシンプルです。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as path from 'path';
export class UsecdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const TargetFunction = new lambda.Function(this, 'TargetFunction',{
runtime: lambda.Runtime.PYTHON_3_9,
handler: 'app.lambda_handler',
code: lambda.Code.fromAsset(path.join(__dirname,'../functions/'))
});
// Function URL
const fnUrl = TargetFunction.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
});
// URLをアウトプット
new cdk.CfnOutput(this,'TargetFunctionUrl',{
value: fnUrl.url,
});
}
}
先に記載したCFnテンプレートとSAMとは以下の点が異なりますが、Function URLの例には影響ないので除きました。
- Lambda用のロールは作成しない
- 自動で
AWSLambdaBasicExecutionRole
がアタッチされます
- 自動で
- Lambda用のロググループは作成しない
- CFnテンプレート変換時に以下のプロパティで上書きされてしまったので定義しませんでした
- 保持期間:1年
- 削除ポリシー: RETAIN
- CFnテンプレート変換時に以下のプロパティで上書きされてしまったので定義しませんでした
使用するLambda関数はfunctions
フォルダ内に置きます。
functions/app.py
def lambda_handler(event, context):
print('sample function')
return {
'statusCode': 200,
'body': 'Hello from Lambda!'
}
あとはコンパイルして変換してデプロイになります。方法は昔まとめた記事がありますのでそちらをご確認ください。
おわりに
今回、ちょっと使ってみたくて触った内容を記事にしました。
どなたかの助けになれば幸いです。