Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8691

【Node.js】JTW生成処理をSAMで作る

$
0
0

前回の続きです。
Zoom会議をSlackをお知らせするアプリにてZoom APIに必要なJWTを生成する処理をSAMで作成しました。(下図の赤枠)
時間ができたらやりたいと思っていましたが、思ったよりすぐやっちゃいました。さすがStayHome週間(笑)
※本記事ではSAM,SAM-CLIなどの詳述は割愛します。ご了承ください。
スクリーンショット 2020-05-06 11.28.57.png

SAMを始める

公式にもありますが、まず↓のような前提があるので、それぞれやっておきます。

  1. AWSアカウントの作成
  2. IAMの設定
  3. Dockerのインストール(ローカル実行に必要)
  4. Homebrewのインストール(Linux,mac)
  5. SAM CLIのインストール

SAMテンプレートの取得

まずは、SAMテンプレートをDLしてきます。

sam init

これを実行します。今回ランタイムはNode.js 12.Xを選択しました。
テンプレートを取得すると以下のような感じのフォルダ構成で展開されるので、適宜編集しながら、処理を実装します。

sam-app/
   ├── README.md
   ├── events/
   │   └── event.json
   ├── hello_world/          
   │   └── app.js            #Contains your AWS Lambda handler logic.
   ├── template.yaml         #Contains the AWS SAM template defining your application's AWS resources.
   └── tests/
       └── unit/
           └── test-handler.js

JWT生成処理

↓のようなコードになります。

app.js
constjwt=require('jsonwebtoken')letresponse;constapiKey=process.env.API_KEY;constsecretKey=process.env.SECRET_KEY;/**
 *
 * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
 * @param {Object} event - API Gateway Lambda Proxy Input Format
 *
 * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html 
 * @param {Object} context
 *
 * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
 * @returns {Object} object - API Gateway Lambda Proxy Output Format
 * 
 */exports.lambdaHandler=async(event,context)=>{returnthis.generateJWT(apiKey,secretKey)};exports.generateJWT=function(apiKey,secretKey){try{// const ret = await axios(url);expire=Math.floor(Date.now())+(60000*15);consttoken=jwt.sign({iss:apiKey,exp:expire},secretKey,{algorithm:'HS256'});response={'statusCode':200,'jwt':token}}catch(err){console.log(err);response={'statusCode':500,'jwt':null}}returnresponse};

node-jsonwebtokenをいうAuth0のライブラリを用いてJWT生成処理を実装しています。

npm install jsonwebtoken

jwt.sign({iss: apiKey,exp: expire}, secretKey, {algorithm: 'HS256'});がJWT生成部分になるワケですが、issにZoomのAPIキー、expにはトークンがエクスパイアするまでの時間を入れます。エクスパイアする時間はエポックミリ秒で指定します。今回は、15分後を指定しています。

そして、生成したJWTを返すワケです。

SAMのデプロイ

ローカル実行

ローカルテストにあたり擬似的に環境変数を与えてやる必要があります。
ざっくりとした理解ですが、ローカルにLambda環境を模したコンテナを建てるので、そこではローカルホストの環境変数は使えないワケですね。

そのため、以下のような環境変数用の設定ファイルを用意しました。

env.json
{"GenerateJWT":{"ApiKey":"XXX","SecretKey":"XXX"}}

そして、template.yamlに↓を追加しましょう。

Resources:GenerateJWT:Type:AWS::Serverless::FunctionProperties:CodeUri:generate-jwt/Handler:app.lambdaHandlerRuntime:nodejs12.x#ここからEnvironment:Variables:API_KEY:!RefApiKeySECRET_KEY:!RefSecretKey#ここまで  

では、ローカルでテストしてみましょう!

まずは

sam build

ビルドして

sam local invoke --env-vars generate-jwt/env.json

generate-jwt/env.jsonを環境変数をして渡しています。
このやり方は以下のブログを参考にさせていただきました。

AWS SAM Local と LocalStack を使って ローカルでAWS Lambdaのコードを動かす

デプロイ

デプロイは簡単です。

sam deploy --guided

これだけ。あとはガイドに従いながら、質問に答えていくだけです。SAM-CLI素晴らしい。
ガイド内容はStack名は?とかリージョンは?とか。↓のように回答していきます。

Deploying with following values
===============================
Stack name                 : generateJWT
Region                     : ap-northeast-1
Confirm changeset          : True
Deployment s3 bucket       : 
Capabilities               : ["CAPABILITY_IAM"]
Parameter overrides        : {'ApiKey': '', 'SecretKey': ''}

このタイミングで今回のtemplate.yamlを載せておきます。

template.yaml
AWSTemplateFormatVersion:'2010-09-09'Transform:AWS::Serverless-2016-10-31Description:>GenerateJWT# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rstGlobals:Function:Timeout:3Resources:GenerateJWT:Type:AWS::Serverless::Function# More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunctionProperties:CodeUri:generate-jwt/Handler:app.lambdaHandlerRuntime:nodejs12.xEnvironment:Variables:API_KEY:!RefApiKeySECRET_KEY:!RefSecretKey#Events:#  GetJWT:#    Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api#    Properties:#      Path: /jwt#      Method: getParameters:ApiKey:Type:StringSecretKey:Type:StringOutputs:# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function# Find out more about other implicit resources you can reference within SAM# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api#GenerateJWTdApi:#Description: "API Gateway endpoint URL for Prod stage for GenerateJWT function"#Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/jwt/"GenerateJWT:Description:"GenerateJWTLambdaFunctionARN"Value:!GetAttGenerateJWT.ArnGenerateJWTIamRole:Description:"ImplicitIAMRolecreatedforGenerateJWTfunction"Value:!GetAttGenerateJWTRole.Arn

API Gatewayもデフォルトのテンプレートでは作成されるのですが、今回Step Functionsから呼び出すだけなこともあり、外しています。
JWTを返すAPIなんてデプロイしたくないし。

無事デプロイすると以下のようにターミナルに出ます。※更新の際のデプロイ結果です。

CloudFormation events from changeset
---------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                      ResourceType                        LogicalResourceId                   ResourceStatusReason              
---------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS                  AWS::Lambda::Function               GenerateJWT                         -                                 
UPDATE_COMPLETE                     AWS::Lambda::Function               GenerateJWT                         -                                 
UPDATE_COMPLETE_CLEANUP_IN_PROGRE   AWS::CloudFormation::Stack          generateJWT                         -                                 
SS                                                                                                                                            
UPDATE_COMPLETE                     AWS::CloudFormation::Stack          generateJWT                         -                                 
---------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
----------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                      
----------------------------------------------------------------------------------------------------------------------------------------------
Key                 GenerateJWT                                                                                                              
Description         GenerateJWT Lambda Function ARN                                                                                          
Value                                             

Key                 GenerateJWTIamRole                                                                                                       
Description         Implicit IAM Role created for GenerateJWT function                                                                       
Value                                                     
----------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - generateJWT in ap-northeast-1

ところで、Parametersを定義しているApiKeySecretKeyの値がガイドの中で聞かれるのですが、ここでローカルの環境変数としてキー情報を渡してやりたかったのに、上手くできませんでした。。。環境変数はこの中では使えないのかな。。。?

Step Functionsで呼び出す

Step Functionsも今回のLambdaに合わせて下図のように変更しています。JWT処理に失敗すればLambdaが500のステータスコードを返すので、そしたらエラー通知用のSNSトピックにプッシュする感じです。

CloudWatch Eventでサイクル実行

日次で毎朝9時に実行したければ、以下のようにcronを定義します。

0 0 * * ? *

GMTなので、9時間戻し毎日0時を指定します。
今回は朝9時まで待ちきれず12:55に実行させました。お昼休み開ける前にZoom会議を作る!みたいなイメージですかね(笑)

結果は?

スクリーンショット 2020-05-06 14.38.47.png

無事成功しました。
ちなみに「密!」は自作です(笑)密を作らず、人と会うときはオンラインで。


Viewing all articles
Browse latest Browse all 8691

Trending Articles