はじめに
他のAWSサービスに対して自動操作ができるかなど、試しにLambdaを作ってみる際に、都度IAMロールやログの管理を考慮するのが面倒と感じていました。
なので、必要最小限のリソースをCloudFormationで作ることで、削除時にまとめて消せるようにしました。
CloudFormation
各部分の解説をし、全体は最後に記載します。
パラメータ
Parameters:
LambdaFunctionName:
Type: String
Type: AWS::Lambda::Function
ではFunctionNameは任意ですが、本番使用の関数作成時も想定して、名前を付けられるようにしました。
ロググループ
対象のLambda関数の出力先ロググループを作成します。
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${LambdaFunctionName}"
RetentionInDays: 3653 # 未指定時は「失効しない」
Lambda関数の出力先ロググループは/aws/lambda/<関数名>
固定のようです。
コンソールから作る際は、関数にアタッチするIAMロールに作成権限を持たせて、Lambda関数から作るようにしているようです。
CloudFormationスタック削除時にロググループを削除するためここに記載していますが、スタックを削除してもログを残したい場合はこの部分を削除して、IAMロールにロググループ作成権限を付けてください。
IAMロール
ポリシー
Lambda関数に必要な権限の定義です。
Policies:
# CloudWatch
- PolicyName: write-cloudwatchlogs
PolicyDocument:
Version: 2012-10-17
Statement:
# ロググループを作らない場合は、権限を与えて自動で作るようにする。
# - Effect: Allow
# Action: 'logs:CreateLogGroup'
# Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*"
- CloudFormationでロググループを作る場合 = スタック削除時にロググループも削除する場合
- ログストリーム作成とログイベント書き出しの権限が必要です。
- CloudFormationでロググループを作らない場合 = スタック削除しても、ロググループを残す場合
- 先のロググループ削除の部分を削除します。
- コメントアウトしている、ロググループ作成権限を有効化します。
その他、他サービスへの権限が必要な場合、ここに追記していく想定です。
Lambda関数
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):
print('Created ${LambdaFunctionName}.')
「自分の名前をログに出力する」というPythonスクリプトが記載されたLambdaを作成します。
全体
以下を1ファイルにして実行すれば動くはずです。
AWSTemplateFormatVersion: 2010-09-09
# Lambdaの最小構成を作成するCFn。CloudWatch Logsのロググループも一緒に作成する。
# スタック削除時にロググループを残したい場合は、ロググループの部分を削除し、ロールからlogs:CreateLogGroupを有効化する。
Parameters:
LambdaFunctionName:
Type: String
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:CreateLogGroup'
# Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
- 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):
print('Created ${LambdaFunctionName}.')
スクリプト部分のみを修正し、他の設定値を変えていないyamlファイルでも、更新してくれました。
おわりに
最小構成のLambda関数のテンプレートをCloudFormationで作成しました。
試しに作ってみる場合や、関数作成もテンプレート化する際のベースに使っていこうと思います。