Serverless FrameworkでCognito UserPoolの認証をしばくときのメモ

  • 社内向けのサーバーレスなサービスが想定で、API GatewayでセキュアなAPIを作ることを考える。
  • そこでCognito UserPoolを使った場合のメモ

Severless Framework

  auth:
    handler: auth.default
    timeout : 5
    memorySize : 256

  secureCheck:
    handler: handler.secureCheck # 動かすlambda関数名
    timeout : 5
    memorySize : 128
    events:
      - http:
          method: get
          path: secureCheck
          cors : true
          authorizer: auth #authorizer: xxx:xxx:Lambda-Name も可能
          response:
            headers:
              Content-Type: "'application/json'"
            template: $input.path('$')

/secureCheck と云うAPIは,authと云うLambda Functionの認証を経てsecureCheck Functionに至るようになる。
そうでなければ403が返る。

この形式でsecureCheck APIにアクセスするとき、リクエストのAuthorizationヘッダーに
Cognito UserPoolでログイン認証したアクセストークンをつけること。
クライアント側の処理は今回は書かない。

auth.ts

const aws = require("aws-sdk");

var cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({
    apiVersion: '2016-04-18',
    region: 'ap-northeast-1'
});

const auth = (event, context, callback)=> {

    const token = event.authorizationToken != null ? event.authorizationToken : event.headers.Authorization

    var params = {
        AccessToken: token
    };
    cognitoidentityserviceprovider.getUser(params, function (err, data) {
        if (err) {
            console.log(err)
            callback(null, generatePolicy('user', 'Deny', event.methodArn , token));
            //callback(null, generatePolicy('user', 'Allow', event.methodArn, data));
        } else {
            console.log(data)
            callback(null, generatePolicy('user', 'Allow', event.methodArn , token));
        }
        return;
    });
};

//"methodArn":"arn:aws:execute-api:<regionId>:<accountId>:<apiId>/<stage>/<method>/<resourcePath>"
const generatePolicy = function generatePolicy(principalId, effect, resource , token) {
  return {
    principalId:principalId,
    policyDocument: {
      Version: '2012-10-17',
      Statement: [{
        Action: 'execute-api:Invoke',
        Effect: effect,
        Resource: "arn:aws:execute-api:ap-northeast-1:*:<API Gateway Id>/*” //CHECK!! =>  http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/permissions.html#api-gateway-calling-api-permissions
      }]
    }
  };
};

export default  auth;

generatePolicyメソッドで、ユーザーに対して必要なAWSの権限をつけている。
ここでは、該当のAPI GateWayの各エンドポイントのinvoke権がつくように組んだ。

他メモ

Cognito UserPoolのAccessTokenやIdTokenのexpireはぴったり1時間なので、
APIを叩くたびに Cognateアクセストークンのexpireチェック => 必要ならばCognitoのrefresh叩いてToken更新 => セキュアなAPI gateway叩く、というフローを経ることになる。
Dynamoにセッションとか入れとくよりは楽なのだろうけど割とラフに非同期チェーンが入ってめんどくさい。

毎回リクエストヘッダにアクセストークンつけるのも、Ajax以外でのエンドポイントのアクセスが制限されてしまうので、なんとかCookie使う方向で今後模索してみる。

Read More