前回の記事で、 aws-vault
とAWS CLIを連携させて使えるようになりました。
Windows + aws-vaultにて、AWSのアクセスキーを保護し、 AWS CLIを AssumeRole で使えるようにしてみた - メモ的な思考的な
今回は、 aws-vault + Serverless Frameworkを連携させ、AWS Lambda + API Gateway を使ったAPIを作成してみます。
また、Serverless Frameworkでデプロイする時のユーザについて、公式では
Search for and select AdministratorAccess ... Note that the above steps grant the Serverless Framework administrative access to your account. While this makes things simple when you are just starting out, we recommend that you create and use more fine grained permissions once you determine the scope of your serverless applications and move them into production.
https://www.serverless.com/framework/docs/providers/aws/guide/credentials/
と書かれています。
ただ、どのような権限があれば最低限となるのか分からなかったため、試してみることにします。
なお、手動で権限を与えるのは手間なので、今回は AWS CDK for TypeScript を使って必要なIAMまわりを作成し、最後にデプロイ用ユーザに手動で割り当てるだけにします*1。
目次
- 環境
- Node.js環境の構築
- Serverless Frameworkのセットアップ
- Serverless FrameworkでデプロイするためのIAMまわりを考える
- AWS CDKでIAMまわりを作成する
- Serverless Frameworkによる実装
- デプロイと動作確認
- ソースコード
環境
- Windows10 (1909, 18363.1379)
- aws-vault v6.2.0
- Serverless Framework 2.25.2
- Plugin 4.4.3
- SDK 2.3.2
- Components: 3.7.0
- AWS CDK for TypeScript 1.90.1 (build 0aee440)
- nvm-windows 1.1.7
- WindowsにおけるNode.jsのバージョン管理ツール
- Node.js 14.15.5
なお、前回の環境から引き続きで行っているため、
な状況とします。
一方、nvm-windowsやNode.js、CDKは今回初めてインストールするものとします。
Node.js環境の構築
Serverless FrameworkやAWS CDKはNode.jsを使うため、Node.js環境を構築します。
nvm-windowsのインストール
Node.jsをそのままインストールしてもよいのですが、今後色々試すことを考えて複数バージョンを使えるようにしておきます。
Windowsではどのようなツールがあるかを調べたところ、以下にまとまっていました。
Windows における Node.js バージョン管理マネージャの選択(nvm-windows, nodist 等) - clock-up-blog
最近見かけるWindowsのパッケージマネージャの一つ Scoop
のMainバケットには何が含まれているかを確認したところ、 nvm-windows
は含まれているものの、nodist
はありませんでした。そこで今回は nvm-windows
を使うことにしました。
https://github.com/ScoopInstaller/Main/blob/master/bucket/nvm.json
次に nvm-windowsのインストールについてです。
Scoopを使ってインストールすることも考えましたが、今後 winget
が登場するとまた変わるのかなと思いました。
https://github.com/microsoft/winget-cli
そこで今回は、Githubから nvm-windows をダウンロード・インストールしました。
https://github.com/coreybutler/nvm-windows
Node.jsのインストール
管理者権限でWindows Terminalを起動し、 nvm-windows
を使ってNode.jsをインストールします。
まずは使えるNode.jsのバージョンを確認します。
>nvm list available | CURRENT | LTS | OLD STABLE | OLD UNSTABLE | |--------------|--------------|--------------|--------------| | 15.9.0 | 14.15.5 | 0.12.18 | 0.11.16 | | 15.8.0 | 14.15.4 | 0.12.17 | 0.11.15 | ... This is a partial list. For a complete list, visit https://nodejs.org/download/release
バージョンリストより、Node.js LTSの最新をインストールします。
>nvm install 14.15.5 Downloading node.js version 14.15.5 (64-bit)... Complete Creating %USERPROFILE%\AppData\Roaming\nvm\temp Downloading npm version 6.14.11... Complete Installing npm v6.14.11... Installation complete. If you want to use this version, type nvm use 14.15.5
使用するNode.jsを有効化し、バージョンを確認します。
>nvm use 14.15.5 Now using node v14.15.5 (64-bit) >node -v v14.15.5
これでNode.jsが使えるようになりました。
Serverless Frameworkのセットアップ
続いてServerless Frameworkをセットアップし、AdministratorAccess権限を持ったユーザでデプロイできるかを確認してみます。
インストール
Node.jsのグローバルにインストールします。
>npm install -g serverless + serverless@2.25.2
動作確認
Serverless Framework の aws-python3
テンプレートを使って、aws-vaultと組み合わせてデプロイできるかを確認してみます。
https://www.serverless.com/framework/docs/providers/aws/guide/services#creation
>serverless create --template aws-python3 --path hello Serverless: Generating boilerplate... Serverless: Generating boilerplate in "path\to\hello" _______ __ | _ .-----.----.--.--.-----.----| .-----.-----.-----. | |___| -__| _| | | -__| _| | -__|__ --|__ --| |____ |_____|__| \___/|_____|__| |__|_____|_____|_____| | | | The Serverless Application Framework | | serverless.com, v2.25.2 -------' Serverless: Successfully generated boilerplate for template: "aws-python3"
デフォルトの serverless.yml
では us-east-1
リージョンにデプロイされてしまうため、東京リージョンへと変更します。
provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 region: ap-northeast-1 # 追加
念のためデプロイ前のLambdaの状態を aws-vault + AWS CLI にて確認してみましたが、何もありません。
>aws-vault exec admin -- aws lambda list-functions { "Functions": [] }
Serverless Frameworkを使って、AdministratorAccess権限にてデプロイしてみます。
aws-vaultと組み合わせて使うので、 aws-vault exec admin -- <serverless frameworkのコマンド>
という形で実行します。
>aws-vault exec admin -- serverless deploy -v ... Serverless: Stack update finished... Service Information service: hello stage: dev region: ap-northeast-1 stack: hello-dev resources: 6 api keys: None endpoints: None functions: hello: hello-dev-hello layers: None Stack Outputs HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:<account_id>:function:hello-dev-hello:1 ServerlessDeploymentBucketName: hello-dev-serverlessdeploymentbucket-xxx
Lambdaもできています。
>aws-vault exec admin -- aws lambda list-functions Enter token for arn:aws:iam::<account_id>:mfa/gate: xxx { "Functions": [ { "FunctionName": "hello-dev-hello", "FunctionArn": "arn:aws:lambda:ap-northeast-1:<account_id>:function:hello-dev-hello", "Runtime": "python3.8", "Role": "arn:aws:iam::<account_id>:role/hello-dev-ap-northeast-1-lambdaRole", "Handler": "handler.hello", "CodeSize": 640, "Description": "", "Timeout": 6, "MemorySize": 1024, "LastModified": "2021-02-21T01:55:02.396+0000", "CodeSha256": "xxx", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "xxx", "PackageType": "Zip" } ] }
続いて、Serverless Frameworkを使って削除してみます。
>av exec admin -- serverless remove -v ... Serverless: Stack delete finished...
Lambdaもなくなっていました。
>aws-vault exec admin -- aws lambda list-functions { "Functions": [] }
Serverless FrameworkでデプロイするためのIAMまわりを考える
ここまでは AdministratorAccess
権限でデプロイしてきました。
ただ、これだと権限が広すぎるため、必要最低限の権限を持つIAMまわりを考えてみます。
必要な権限について
今回は
をServerless Frameworkで自動生成するための権限を考えてみます。
Serverless Frameworkで最低限の権限でデプロイする方法を調べたところ、以下のissueや記事がありました。
- Narrowing the Serverless IAM Deployment Policy · Issue #1439 · serverless/serverless
- Serverless Framework: Minimal IAM role Permissions | by David Przybilla | Medium
- The ABCs of IAM: Managing permissions with Serverless
今回は
- IAMユーザはAssumeRoleする権限を所持
- デプロイする権限やCloudFormationはAssumeRoleして使う
とするため、以下の2つのIAMロールを用意します。
aws-vault exec <profile> -- serverless deploy
するためのIAMロール- デプロイするため上記ロールから、CloudFormationへPassRoleされた時のIAMロール
- Serverless FrameworkはCloudFormationを使ってAWSリソースを構築するため
一方、AWS Lambdaから他のAWSリソースは使わないため、AWS Lambda用のロールはServerless Frameworkで自動生成されるものを使います。
なお、自動生成されるロール(<PROJECT>-<STAGE>-<REGION>-lambdaRole
)は、以下のインラインポリシーを持って生成されます。
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogStream", "logs:CreateLogGroup" ], "Resource": [ "arn:aws:logs:<region>:<account_id>:log-group:/aws/lambda/<PROJECT>-<STAGE>*:*" ], "Effect": "Allow" }, { "Action": [ "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:a<region>:<account_id>:log-group:/aws/lambda/<PROJECT>-<STAGE>*:*:*" ], "Effect": "Allow" } ] }
次に、各IAMロールに必要な権限を考えてみます。
serverless deploy
でできるリソースですが、
serverless deployで何が更新されるのか確認してみました(Serverless Framework / AWS) | DevelopersIO
そのため、各IAMロールで必要な権限を考えてみます*2。
デプロイするための権限を持つIAMロール
デプロイするときは
- CloudFormationを操作する権限
- S3に対して中間ファイルを操作する権限
- CloudFormationにPassRoleする権限
の3つがあれば良さそうです。
また、上記の各権限に対し、Serverless Frameworkで必要な Resource のみに制限します。
CloudFormationのための権限を持つIAMロール
実際のAWSリソースを生成するときは、AWSリソースごとの権限があれば良さそうです。
また、今回はLambdaの権限をServerless Frameworkで生成するため、以下の権限も必要です。
- IAMを操作する権限
- Lambda用ロールにPassRoleする権限
こちらも上記の各権限に対し、Serverless Frameworkで必要な Resource のみに制限します。
その他IAMまわりで必要なもの
デプロイするためのIAMロールですが、デプロイユーザがAssumeRoleできる必要があります。
そのため、
- デプロイするためのIAMロールに対してAssumeRoleできるIAMポリシーを作成
- 上記1.のポリシーを割り当てたIAMグループを作成
- 上記3のグループに、デプロイするユーザを所属させる
も行います。
AWS CDKでIAMまわりを作成する
上記で考えたIAMまわりを手動で作成してもよいのですが、
という問題があります。
そこで、AWS CDK + TypeScriptにてIAMまわりを作成します。
@aws-cdk/aws-iam module · AWS CDK
なお、冒頭で書いたとおり、グループへの割当は手動のままとします。
AWS CDKまわりの環境構築
CDK本体をインストールします。
>npm install -g aws-cdk + aws-cdk@1.90.1
続いてCDK appを作成します。今回はTypeScriptで作成します。
なお、 cdk init
は空のディレクトリでないと実行できないことから、IAMモジュールの追加は後で行います。
> cdk init app --language typescript ... ✅ All done!
最後に、IAMモジュールをインストールします。
> npm install -S @aws-cdk/aws-iam ... + @aws-cdk/aws-iam@1.90.1
CDK全体の構成
生成されたTypeScriptファイルは、以下の2つがありました。
bin/cdk.ts
lib/cdk-stack.ts
このうち、cdk.tsはcdk-stack.tsに含まれるクラス CdkStack
をインスタンス化しているだけなので、実装は cdk-stack.ts
の CdkStack
クラスに行えば良さそうです。
まずは、CdkStack.ts に全体像を作ります。
今回は複数のリソースを作成することから、各リソースのまとまりごとにメソッドを3つに分割しておきます。
- createRoleForCfn()
- CloudFormation用のIAMロールを作成するメソッド
- createRoleForDeployUser()
- デプロイするユーザがAssumeRoleできるIAMロールを作成するメソッド
- createGroupOfDeployUser()
- デプロイするユーザが所属するIAMグループを作成するメソッド
import * as cdk from '@aws-cdk/core'; import IAM = require('@aws-cdk/aws-iam') import { Effect } from '@aws-cdk/aws-iam'; // Serverless Frameworkのプロジェクトとステージ const PROJECT = 'hello-sls' const STAGE = '*' // どのステージにも適用できるようにした(必要に応じて、ステージを分ける) export class CdkStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const cfnRole = this.createRoleForCfn(); const deployRole = this.createRoleForDeployUser(cfnRole); this.createGroupOfDeployUser(deployRole); } }
CloudFormation用のIAMロールをCDKで実装
デプロイするためのIAMロールを作る際CloudFormation用IAMロールのARNが必要となるため、まずはCloudFormation用から作成します。
作成順は
となります。
IAMポリシーのステートメント群を作成
IAM.PolicyStatement
クラスを使って、IAMポリシーのステートメントを1つずつ作成していきます。
AWSアカウントIDは this.account
、リージョンは this.region
でそれぞれ参照できます。
また、resourcesで今回使うServerless Frameworkのリソースだけに絞ります。
なお、API Gatewayの場合、ResourceだけではServerless Frameworkのリソースのみに限定できなかったため、広めの権限を与えています。
// CFnでリソースを操作するロールを作成 createRoleForCfn(): IAM.Role { const statements = []; // Serverless FrameworkがLambda用Roleを作るときに、権限を渡してあげる statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'iam:PassRole' ], resources: [ `arn:aws:iam::${this.account}:role/${PROJECT}-${STAGE}-${this.region}-lambdaRole` ] })); // CFnがS3からデータを取得できるようにする statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:*' ], resources: [ `arn:aws:s3:::${PROJECT}-${STAGE}`, `arn:aws:s3:::${PROJECT}-${STAGE}/`, ] })); statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:ListAllMyBuckets', 's3:CreateBucket', ], resources: [ '*' ] })); // API Gatewayまわりの権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'apigateway:GET', 'apigateway:PATCH', 'apigateway:POST', 'apigateway:PUT', 'apigateway:DELETE' ], resources: [ `arn:aws:apigateway:${this.region}::/restapis`, `arn:aws:apigateway:${this.region}::/restapis/*` ] })); // Lambdaがログを出力する先であるCloudWatchまわりの権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'logs:DescribeLogGroups', ], resources: [ `arn:aws:logs:${this.region}:${this.account}:log-group::log-stream:*` ] })); statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:DeleteLogGroup', 'logs:DeleteLogStream', 'logs:DescribeLogStreams', 'logs:FilterLogEvents' ], resources: [ `arn:aws:logs:${this.region}:${this.account}:log-group:/aws/lambda/${PROJECT}-${STAGE}:log-stream:*` ] })); // Serverless FrameworkがLambda用ロールを扱えるようにするための権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ "iam:GetRole", "iam:GetRolePolicy", "iam:CreateRole", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:PutRolePolicy" ], resources: [ `arn:aws:iam::${this.account}:role/${PROJECT}-${STAGE}-${this.region}-lambdaRole` ] })); // Lambdaまわりの権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'lambda:GetFunction', 'lambda:CreateFunction', 'lambda:DeleteFunction', 'lambda:UpdateFunctionConfiguration', 'lambda:UpdateFunctionCode', 'lambda:ListVersionsByFunction', 'lambda:PublishVersion', 'lambda:CreateAlias', 'lambda:DeleteAlias', 'lambda:UpdateAlias', 'lambda:GetFunctionConfiguration', 'lambda:AddPermission', 'lambda:RemovePermission', 'lambda:InvokeFunction' ], resources: [ `arn:aws:lambda:${this.region}:${this.account}:function:${PROJECT}-${STAGE}` ] })); // 2. ステートメントをまとめたユーザ管理ポリシーを書く // 3. ユーザ管理ポリシーを含めたIAMロール }
ステートメントをまとめたユーザ管理ポリシー
続いて、ステートメントをまとめたユーザ管理ポリシーを IAM.ManagedPolicy
クラスを使って実装します。
statementesに、ステートメント群を指定します。
const cfnPolicy = new IAM.ManagedPolicy( this, 'thinkAmiCfnPolicy', { managedPolicyName: 'thinkAmi-Serverless-CFn', statements: statements } );
ユーザ管理ポリシーを含めたIAMロール
最後にIAMロールを作成します。
assumedBy
にて、CloudFormationでしか使えないように指定します。なお、CloudFormationはAWSのサービスのため、 assumedBy
で使うクラスは IAM.ServicePrincipal
です。
return new IAM.Role( this, 'thinkAmiCfnRole', { roleName: 'thinkAmi-Serverless-CFn-Role', assumedBy: new IAM.ServicePrincipal('cloudformation.amazonaws.com'), managedPolicies: [ cfnPolicy ] } );
デプロイするためのIAMロール
次に、デプロイするためのIAMロールを作成します。
作成順はCloudFormation用のIAMロールと同様です。
IAMポリシーのステートメント群
CloudFormationで作成するAWSリソースに対する権限はCloudFormation用のIAMロールに任せるため、 iam:PassRole
します。
あとは必要な権限を追加します。
// Serverless FrameworkでAWSリソースを扱うためのロールを作成 createRoleForDeployUser(cfnRole: IAM.Role): IAM.Role { const statements = [] // CFnでのリソース作成をCFn用ロールにPassRoleする権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'iam:PassRole', ], resources: [ cfnRole.roleArn ] })); // S3を使ってデプロイするための権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:*', ], resources: [ `arn:aws:s3:::${PROJECT}-${STAGE}`, `arn:aws:s3:::${PROJECT}-${STAGE}/*` ] })); statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:ListAllMyBuckets', 's3:CreateBucket' ], resources: [ '*' ] })); // CFnを扱うための権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'cloudformation:CreateStack', 'cloudformation:UpdateStack', 'cloudformation:DeleteStack' ], resources: [ `arn:aws:cloudformation:${this.region}:${this.account}:stack/${PROJECT}-${STAGE}/*` ] })); statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'cloudformation:Describe*', 'cloudformation:List*', 'cloudformation:Get*', 'cloudformation:ValidateTemplate' ], resources: [ '*' ] })); // Paramter Storeから値を取得する権限 // serverless.yml中のdeploymentRoleにて指定するARNをParamter Storeに設定する statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'ssm:GetParameter' ], resources: [ `arn:aws:ssm:${this.region}:${this.account}:parameter/hello-sls/CFn-Role` ] })); // ... }
ステートメントをまとめたユーザ管理ポリシー
書き方はCloudFormationのときと同じです。
// ユーザ管理ポリシーとして作成 const deployPolicy = new IAM.ManagedPolicy( this, 'thinkAmiDeployPolicy', { managedPolicyName: 'thinkAmi-Serverless-Deploy', statements: statements } );
ユーザ管理ポリシーを含めたIAMロール
同じようにIAMロールを作成します。
ただ、AssumeRoleの対象がアカウントIDであるため、 IAM.AccountPrincipal
クラスに this.account
を渡しています。
// デプロイするユーザ用ロールとして作成 return new IAM.Role( this, 'thinkAmiDeployRole', { roleName: 'thinkAmi-Serverless-Deploy-Role', assumedBy: new IAM.AccountPrincipal(this.account), managedPolicies: [deployPolicy] } );
デプロイするユーザが所属するグループを作成
デプロイ用IAMロールに対してAssumeRoleできるIAMポリシーをIAMグループに割り当てます。
// Deployするユーザが所属するグループを作成 // Serverless FrameworkでAWSリソースを扱うためのロールに対してAssumeRoleできる権限を、このグループに割り当てる createGroupOfDeployUser(deployRole: IAM.Role) { const statements = []; // AssumeRoleする権限 statements.push(new IAM.PolicyStatement({ effect: Effect.ALLOW, actions: [ 'sts:AssumeRole' ], resources: [ deployRole.roleArn ] })); // ユーザ管理ポリシーとして作成 const assumePolicy = new IAM.ManagedPolicy( this, 'thinkAmiAssumePolicy', { managedPolicyName: 'thinkAmi-Serverless-Assume-By-User', statements: statements } ); // グループに割り当て new IAM.Group( this, 'thinkAmiAssumeGroup', { groupName: 'thinkAmi-Serverless-Assume', managedPolicies:[assumePolicy] } ); }
CloudFormationテンプレートの確認
cdk synth
を使うことで、CDKで実装した内容がCloudFormationテンプレートとして表示されます。
そのため、CDKでデプロイする前にCloudFormation用テンプレートを確認できます。
# cdk.json ファイルがある階層で実施 >cdk synth
CDKでのデプロイ
IAMまわりを作成するため、AdministratorAccess権限を持つIAMロールで実行します。
>aws-vault exec admin -- cdk deploy -v ... ✅ CdkStack Stack ARN: arn:aws:cloudformation:<region>:<account_id>:stack/CdkStack/xxx
手動での設定
ユーザをグループに割り当て
手動にて、 thinkAmi-Serverless-Assume
グループへデプロイユーザを割り当てます。
aws-vault用にデプロイロール設定を追加
既存のgateユーザがデプロイロールを使えるようにするため、 .aws\config
へ追記します。
[default] region=ap-northeast-1 output=json [profile gate] # 以下を追加 [profile hello] source_profile = gate role_arn = <thinkAmi-Serverless-Deploy-RoleのARN> role_session_name = thinkAmiHelloDeploy mfa_serial = <gateユーザが持つMFAのARN>
Systems ManagerのParameter Storeにデプロイ用ロールのARNをセット
デプロイ用ロールのARNをserverless.ymlに設定する必要があるものの、ARNの値をハードコーディングしたくありません。
そこで今回は、Systems ManagerのParameter Storeに値を手動で設定します。
Secrets Management for AWS Powered Serverless Applications
名前 | 値 | 種類 |
---|---|---|
/hello-sls/CFn-Role | デプロイ用IAM RoleのARN | SecureString |
ここまでで、Serverless Frameworkでデプロイするのに必要な権限まわりの準備は終わりました。
Serverless Frameworkによる実装
続いて、Serverless Framewrokでの設定を行います。
serverless.yamlでの設定
Serverless FrameworkでデプロイするAWSリソースなどを serverless.yml
に記載します。
serviceまわり
service名は hello-sls
とします。
また、frameworkVersionはデフォルトの 2
のままとします。
なお、Serverless Frameworkの2系では、Parameter Storeから値が取得できなくてもデプロイが継続されてしまいます。
一方、今後リリースされる3系ではエラーになるようです。
https://www.serverless.com/framework/docs/deprecations/#PROVIDER_IAM_SETTINGS
そこで今回は、3系と同じくParameter Storeより値が取得できなければエラーとなるように設定します。
service: hello-sls frameworkVersion: '2' # Parameter Storeより値が取得できなければエラー unresolvedVariablesNotificationMode: error
provider
通常設定するものの他、Serverless Framework 3系の機能を先取りするよう設定します。
まずはAPI Gatewayの名前を <service>-<stage>
とするよう、 apiGateway.shouldStartNameWithService
を設定します。
https://www.serverless.com/framework/docs/deprecations/#AWS_API_GATEWAY_NAME_STARTING_WITH_SERVICE
また、Serverless FrameworkでCloudFormationを実行するRoleの指定について、今までは provider.cfnRole
だったものが今後は provider.iam.deploymentRole
になるため、その変更も行います。
https://www.serverless.com/framework/docs/deprecations/#AWS_API_GATEWAY_NAME_STARTING_WITH_SERVICE
なお、 deploymentRole
の値は Parameter Storeから取得するように指定します。
Secrets Management for AWS Powered Serverless Applications
今回のParamter Storeは SecureString
としたため、serverless.ymlで指定する場合は末尾に ~true
を付与します。
provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 region: ap-northeast-1 stage: development apiGateway: shouldStartNameWithService: true iam: deploymentRole: ${ssm:/hello-sls/CFn-Role~true}
functions
ここからはAPI GatewayとLambdaの設定を行います。
handler.py
の hello
関数をLambdaで実行するための設定を行います。
functions: hello: handler: handler.hello
また、API Gatewayも作成します。今回は以下の内容でAPI Gatewayを作成します。
項目 | 値 |
---|---|
パス | /req |
メソッド | GET |
統合リクエスト | Lambda |
マッピングテンプレート - リクエスト本文のパススルー | リクエストの Content-Type ヘッダーに一致するテンプレートがない場合 |
マッピングテンプレート | 定義なし |
serverless.ymlでは以下の通りになります。
なお、 template
では2つのContent-Typeに null
を設定しています。何も設定しないとデフォルトのテンプレートが設定されてしまうためです。
https://www.serverless.com/framework/docs/providers/aws/events/apigateway#custom-request-templates
functions: hello: handler: handler.hello events: - http: path: req method: get integration: lambda request: passThrough: WHEN_NO_MATCH template: application/json: null application/x-www-form-urlencoded: null
詳細は公式ドキュメントにも記載があります。
Serverless Framework - AWS Lambda Events - API Gateway
以上で serverless.yml
の設定は完了です。
Lambdaの実装
serverless.yml
に設定した handler.py
を実装します。
今回は動作確認が取れれば良いので、生成されたLambdaをそのまま使います。
import json def hello(event, context): body = { "message": "Go Serverless v1.0! Your function executed successfully!", "input": event } response = { "statusCode": 200, "body": json.dumps(body) } return response # Use this code if you don't use the http event with the LAMBDA-PROXY # integration """ return { "message": "Go Serverless v1.0! Your function executed successfully!", "event": event } """
デプロイと動作確認
デプロイ
ここまでで準備ができたため、Serverless Frameworkによるデプロイを行います。
デプロイが成功すると、Service Informationが表示されます。
>aws-vault exec hello -- serverless deploy -v Enter token for arn:aws:iam::<account_id>:mfa/<user>: xxx ... Serverless: Stack update finished... Service Information service: hello-sls stage: development region: ap-northeast-1 stack: hello-sls-development resources: 11 api keys: None endpoints: GET - https://path.to.ap-northeast-1.amazonaws.com/development/req functions: hello: hello-sls-development-hello layers: None Stack Outputs HelloLambdaFunctionQualifiedArn: arn:aws:lambda:<region>:<account_id>:function:hello-sls-development-hello:8 ServiceEndpoint: https://path.to.ap-northeast-1.amazonaws.com/development ServerlessDeploymentBucketName: hello-sls-development-serverlessdeploymentbucket-xxx
動作確認
ここまでで Lambda + API GatewayなAPIができました。
curl
でアクセスしてみたところ、APIが動作するのを確認できました。
>curl -i https://path.to.ap-northeast-1.amazonaws.com/development/req HTTP/1.1 200 OK Content-Type: application/json Content-Length: 121 ... {"statusCode": 200, "body": "{\"message\": \"Go Serverless v1.0! Your function executed successfully!\", \"input\": {}}"}
ソースコード
Githubに上げました。
https://github.com/thinkAmi-sandbox/sls_hello_with_cdk_by_min_perm