はじめに
以前、Microsoft365の監査ログを取得するLambdaをコンテナで作りました。
これを以下のページを参考に、Cloud9上でAWS SAM CLIでのデプロイにチャレンジしてみました。
所感
- AWS SAM CLIを用いると、デプロイまでの手間が減る
- 特に、ECRの作成や管理を考えなくてよいのが大変助かる
- 上記ページでは作っていますが、現時点では不要のようです
- 特に、ECRの作成や管理を考えなくてよいのが大変助かる
- (Cloud9上の)AWS Toolkitのウィザードでも試しましたが、launch.json を使ったデバッグ実行がうまくいかなかった
- AWS SAM CLIのナビゲーションで十分便利なので、GUIのウィザードを使わなくてもよいかも
環境
- Cloud9
- コンテナを使うのでそこそこのものを
- Lambdaのコンテナを作ったものと同じ環境です
やったこと
前提
必要なスクリプト等はすべて作成済みとします。以前の記事でdocker build
の前の状態までになります。
プロジェクト作成
いきなりsam init
から始めます。指示の中でProject nameを問われ、そのディレクトリ以下に展開されます。
$ sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2
Which base image would you like to use?
1 - amazon/nodejs14.x-base
2 - amazon/nodejs12.x-base
3 - amazon/nodejs10.x-base
4 - amazon/python3.9-base
5 - amazon/python3.8-base
6 - amazon/python3.7-base
7 - amazon/python3.6-base
8 - amazon/python2.7-base
9 - amazon/ruby2.7-base
10 - amazon/ruby2.5-base
11 - amazon/go1.x-base
12 - amazon/java11-base
13 - amazon/java8.al2-base
14 - amazon/java8-base
15 - amazon/dotnet5.0-base
16 - amazon/dotnetcore3.1-base
17 - amazon/dotnetcore2.1-base
Base image: 4
Project name [sam-app]: get-ms365auditlog
Cloning from https://github.com/aws/aws-sam-cli-app-templates
AWS quick start application templates:
1 - Hello World Lambda Image Example
2 - PyTorch Machine Learning Inference API
3 - Scikit-learn Machine Learning Inference API
4 - Tensorflow Machine Learning Inference API
5 - XGBoost Machine Learning Inference API
Template selection: 1
作成されたプロジェクトディレクトリは以下の用にファイルが配置されています。
参考ページにあるとおりにほとんど削除し、必要なものをコピーして以下の様にしました。(RIEは今回使いません。)
sam build
template.yamlを以下のように書き換えました。
Outputsを指定していますが、今回は使いません(いずれ使うことがあるかと思い記載しています)。
クリックで表示
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
Get Audit Log from MS365
Parameters:
GetAuditLogFunctionName:
Type: String
TargetBucket:
Type: String
TargetParameterStore:
Type: String
Globals:
Function:
Timeout: 900
Resources:
########################################################
### GetAuditLogFunction
########################################################
# Log Group
GetAuditLogFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${GetAuditLogFunctionName}"
RetentionInDays: 3653
# IAM Role
GetAuditLogFunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "for-lambdafunction-${GetAuditLogFunctionName}"
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/${GetAuditLogFunctionName}:*"
# S3
- PolicyName: write-s3object
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
Resource: !Sub "arn:aws:s3:::${TargetBucket}/*"
# SSM Parameter Store
- PolicyName: get-ssmparameter
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'ssm:GetParameter'
Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${TargetParameterStore}"
# Lambda Function
GetAuditLogFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref GetAuditLogFunctionName
Role: !GetAtt GetAuditLogFunctionRole.Arn
MemorySize: 384
PackageType: Image
Architectures:
- x86_64
Environment:
Variables:
SSMPARAMETERNAME: !Ref TargetParameterStore
Metadata:
Dockerfile: Dockerfile
DockerContext: ./src/
DockerTag: get-ms365auditlog
Outputs:
GetAuditLogFunction:
Description: "Get Audit Log Lambda Function ARN"
Value: !GetAtt GetAuditLogFunction.Arn
# GetAuditLogFunctionIamRole:
# Description: "Implicit IAM Role created for GetAuditLogFunction"
# Value: !GetAtt GetAuditLogFunctionRole.Arn
一度に全て書いていますが、小さい部分から少しずつ作成する場合は、”Lambdaで環境変数を使用する場合はその旨明示しておき、Buildする”必要があります。
明示しないままだと、この後のlocal invokeにて環境変数が指定できません。
問題なければBuildします。docker buildと同様に、イメージが作られます。
sam build
sam local invoke
作られたイメージを使って、SAM CLIのローカル環境での実行機能から実行してみます。
与えるイベントや環境変数はファイルに作成して、実行時のコマンドで渡す形になります。
{
"StartDate":"2022-08-24 15:00:00",
"EndDate":"2022-08-24 15:59:59",
"BucketName":"<<BUCKET_NAME>>",
"Key":"testwrite/20220824150000.json"
}
環境変数を指定するファイルの記載は公式にあります。
今回はtemplate.yamlのLambda関数の論理IDを指定しています。
{
"GetAuditLogFunction": {
"SSMPARAMETERNAME": "GetMs365AuditLog-ExchangeOnlineParameters"
}
}
実行は以下のコマンドになります。
sam local invoke -n vars.json -e events/event.json
sam deploy
問題なければDeployです。事前にECRを作っておく必要はありません。
今回はIAM roleも作るので、--capabilities CAPABILITY_NAMED_IAM
が必要になります。
sam deploy --guided --capabilities CAPABILITY_NAMED_IAM
あとはナビゲーション通りに入力するだけです。
実行
以前と同様に実行できます。
# リージョンとアカウントIDを環境変数にセット
REGION="ap-northeast-1"
BUCKETNAME="<<BUCKET_NAME>>"
# 実行
aws lambda invoke \
--function-name get-ms365auditlog \
--payload "{
\"StartDate\":\"2022-08-24 15:00:00\",
\"EndDate\":\"2022-08-24 15:59:59\",
\"BucketName\":\"${BUCKETNAME}\",
\"Key\":\"testwrite/20220824150000.json\"
}"\
--region ${REGION} output ; cat output
変更
コードを変更して反映するまでを試してみました。
ログがうるさいのでSTDOUTは出さないようにしてみました。
(前略)
cmd = ['pwsh', '-Command', f'/script/GetMs365AuditLog.ps1 {encoded_event_and_context}']
o = subprocess.run(cmd, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# stdout = o.stdout.strip()
stdout = ""
stderr = o.stderr.strip()
logger.info( json.dumps(stdout, ensure_ascii=False, indent=2) )
logger.info( json.dumps(stderr, ensure_ascii=False, indent=2) )
(後略)
コマンドはBuildして、(必要に応じてローカル実行して、)Deployするだけになります。
Deployの設定は初回の内容をファイル保存していれば、それがデフォルト値になり、Enterしているだけで済みました。
sam build
# 必要であれば
sam local invoke -n vars.json -e events/event.json
# 初回の設定がデフォルト値に。基本Enter連打
sam deploy --guided --capabilities CAPABILITY_NAMED_IAM
aws lambda invoke \
--function-name get-ms365auditlog \
--payload "{
\"StartDate\":\"2022-08-24 15:00:00\",
\"EndDate\":\"2022-08-24 15:59:59\",
\"BucketName\":\"${BUCKETNAME}\",
\"Key\":\"testwrite/20220824150000.json\"
}"\
--region ${REGION} output ; cat output
片づけ
sam delete
一つで、CFnや自動作成されたECRまで消してくれます。
$ sam delete
Are you sure you want to delete the stack teststack20220825 in the region ap-northeast-1 ? [y/N]: y
Are you sure you want to delete the folder teststack20220825 in S3 which contains the artifacts? [y/N]: y
Found ECR Companion Stack teststack20220825-1c6a0a04-CompanionStack
Do you you want to delete the ECR companion stack teststack20220825-1c6a0a04-CompanionStack in the region ap-northeast-1 ? [y/N]: y
ECR repository <<ECRリポジトリ名>> may not be empty. Do you want to delete the repository and all the images in it ? [y/N]: y
ロールもロググループもLambdaも削除される(Lambdaだけ画像無し)。
あとはdocker images
とdocker rmi
で対象のイメージを削除していけば全部消えます。
おわりに
今回はコンテナLambdaをSAMでデプロイする方法を試してみました。
以前のbashのコマンドによる方法と比べて、かなり簡単に作成・変更ができました。
大変便利なので、本番ではこれを使って運用していきたいと思います。