0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-05-06

前回の続きです。
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
const jwt = require('jsonwebtoken')

let response;

const apiKey = process.env.API_KEY;
const secretKey = 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) => {
    return this.generateJWT(apiKey, secretKey)
};

exports.generateJWT = function (apiKey, secretKey) {
    try {
        // const ret = await axios(url);
        expire = Math.floor(Date.now()) + (60000 * 15);
        const token = jwt.sign({
            iss: apiKey,
            exp: expire
        }, secretKey, {
            algorithm: 'HS256'
        });
        response = {
            'statusCode': 200,
            'jwt': token
        }
    } catch (err) {
        console.log(err);
        response = {
            'statusCode': 500,
            'jwt': null
        }
    }
    return response
};

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::Function
    Properties:
      CodeUri: generate-jwt/
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      #ここから
      Environment:
        Variables:
          API_KEY: !Ref ApiKey
          SECRET_KEY: !Ref SecretKey
      #ここまで  

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

まずは

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-31
Description: >
  GenerateJWT
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  GenerateJWT:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: generate-jwt/
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      Environment:
        Variables:
          API_KEY: !Ref ApiKey
          SECRET_KEY: !Ref SecretKey
      #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: get

Parameters:
  ApiKey:
    Type: String
  SecretKey:
    Type: String

Outputs:
  # 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: "GenerateJWT Lambda Function ARN"
    Value: !GetAtt GenerateJWT.Arn
  GenerateJWTIamRole:
    Description: "Implicit IAM Role created for GenerateJWT function"
    Value: !GetAtt GenerateJWTRole.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

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?