【Serverless Framework入門】認証付きAPIを作成する


Serverless Frameworkの存在を最近知ったので、
公式のチュートリアルを見て、AWSで認証付きのAPI(HTTP)を作成してみました。

Serverless Frameworkについて

Serverless Frameworkとは

サーバーレスアプリケーションの開発フレームワーク。
様々なクラウドベンダーに対応している。

基本的な使い方

  • serverless.ymlに構成を記述
  • 本体の関数を用意
  • デプロイ

導入すると何がうれしいのか

デプロイが自動化されることで、時間短縮になる

コマンド一発でデプロイ可能になります。
アプリケーション開発中は何度もデプロイを行うことになるので、トータルで見ると大きな工数削減となります。

インフラをコードで管理できる

いわゆるInfrastructure as Code
開発者はサーバーの出来上がりの姿をコードに記述するだけでよく、実際の構築はフレームワークがよろしくやってくれます。
そのため、構築作業による人為的なミスが発生しません。
また、変更を加えたときに、どこがどう変わったのか明確になります。

やってみた

Serverless Frameworkをインストール

npm install -g serverless

実装

serverless.ymlに構成を記述

serverless.yml
service: http-api-node

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-1
  environment:
    DOMAIN_SUFFIX: kaoki
  httpApi:
    authorizers:
      serviceAuthorizer:
        identitySource: $request.header.Authorization
        issuerUrl: 
          Fn::Join:
          - ''
          - - 'https://cognito-idp.'
            - '${opt:region, self:provider.region}'
            - '.amazonaws.com/'
            - Ref: serviceUserPool
        audience:
          - Ref: serviceUserPoolClient
functions:
  getProfileInfo:
    handler: profile.get
    events:
      - httpApi:
            method: GET
            path: /user/profile
            authorizer: serviceAuthorizer
  createProfileInfo:
    handler: profile.post
    events:
      - httpApi:
            method: POST
            path: /user/profile
            authorizer: serviceAuthorizer

resources:
  Resources:
    HttpApi:
      DependsOn: serviceUserPool
    serviceUserPool:
      Type: AWS::Cognito::UserPool
      Properties:
        UserPoolName: service-user-pool-${opt:stage, self:provider.stage}
        UsernameAttributes:
          - email
        AutoVerifiedAttributes:
          - email
    serviceUserPoolClient:
      Type: AWS::Cognito::UserPoolClient
      Properties:
        ClientName: service-user-pool-client-${opt:stage, self:provider.stage}
        AllowedOAuthFlows:
          - implicit
        AllowedOAuthFlowsUserPoolClient: true
        AllowedOAuthScopes:
          - phone
          - email
          - openid
          - profile
          - aws.cognito.signin.user.admin
        UserPoolId:
          Ref: serviceUserPool
        CallbackURLs: 
          - https://localhost:3000
        ExplicitAuthFlows:
          - ALLOW_USER_SRP_AUTH
          - ALLOW_REFRESH_TOKEN_AUTH
        GenerateSecret: false
        SupportedIdentityProviders: 
          - COGNITO
    serviceUserPoolDomain:
      Type: AWS::Cognito::UserPoolDomain 
      Properties:
        UserPoolId: 
          Ref: serviceUserPool
        Domain: service-user-pool-domain-${opt:stage, self:provider.stage}-${self:provider.environment.DOMAIN_SUFFIX}

Lambda関数

profile.js
'use strict';

module.exports.get = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: event,
    }),
  };
  callback(null, response);
};

module.exports.post = (event, context, callback) => { 
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Password sent.',
    }),
  };
  callback(null, response);
};

デプロイ

sls deploy

裏ではCloudFormationが動いているようでした。
デプロイが完了すると、APIのエンドポイントが出力されます。

endpoints:
  GET - https://66q56zs3l7.execute-api.ap-northeast-1.amazonaws.com/user/profile
  POST - https://66q56zs3l7.execute-api.ap-northeast-1.amazonaws.com/user/profile
functions:
  getProfileInfo: http-api-node-dev-getProfileInfo
  createProfileInfo: http-api-node-dev-createProfileInfo

IDトークンの取得

デプロイすると、service-user-pool-devという名前でCognitoユーザープールが自動で作成されます。
アプリクライアントの設定 > ホストされたUIを起動から認証を行い、発行されるIDトークンをメモします。

テスト

以上でAPIが叩けるようになりました。
IDトークンをAuthorizationヘッダに付与し、エンドポイントにアクセスすると無事レスポンスが返ってくることが確認できました。

片付け

デプロイ同様、削除も簡単にできます。

sls remove

感想

かなり簡単に認証付きのAPIが作れてしまいました。
クラウドの周辺知識は必要ですが、Serverless Framework自体の学習コストは高くなく、かなり良さげだと思います。
よくあるアプリケーション構築パターン別のテンプレートが用意されているのも良いと思いました。
もう少し深堀って学習したいと思います。

参考

https://serverless.com/
https://serverless.com/blog/serverless-auth-with-aws-http-apis