🛤️

Severless Framework + TypeScriptでAppSyncのLambda認証をする

2021/11/08に公開

Serverless frameworkのAppSyncプラグインでもlambda認証が設定できるようになっているので動作を確認してみました。

基本的な設定は以前の記事と大体一緒です。
https://zenn.dev/merutin/articles/02960a57bb8947

作成元のソースはServerless Framework + TypeScriptでAppSync環境構築するの記事を参照してください

結論

  • AppSyncのプラグインでAWS上に正しくデプロイはできる
  • ただし、serverless offlineはまだ動作しないので、ローカルで開発するにはちょっとしんどい。

実装

ソースはGithubにあるので、参考にどうぞ
https://github.com/merutin/serverless-appsync-lambda-test/tree/lambda-auth

lambda

src/handler.ts
export const sampleAuth = async (event: any) => {
  console.log(`event >`, JSON.stringify(event, null, 2));
  const {
    authorizationToken,
    requestContext: { apiId, accountId },
  } = event;

  const response = {
    // ここがfalseの場合は認証失敗になる
    isAuthorized: true,
    // 後続処理に渡せる情報。vtlやリゾルバーに渡す値として利用できる
    // ここで権限チェック系の共通処理の結果を渡してあげるとよさそう
    resolverContext: {
      userid: "test-user-id",
      info: "contextual information A",
      more_info: "contextual information B",
    },
    // 拒否するfieldを選択できる
    deniedFields: [
      // 特定のtypeのフィールドのみを禁止したい場合
      `arn:aws:appsync:${process.env.AWS_REGION}:${accountId}:apis/${apiId}/types/Post/fields/comments`,
      // 特定のmutationを禁止したい場合
      `Mutation.createEvent`,
    ],
    ttlOverride: 10,
  };
  console.log(`response >`, JSON.stringify(response, null, 2));
  return response;
};

graphql

  • sampleクエリの認証タイプだけ変更します
    • 前の時に追加してなかったのに動いてたのなんでだろうか。。
graphql/schema.graphql
type Query {
-	sample: String!
+	sample: String! @aws_lambda
}

serverless.ts

lambda認証に変更するためにserverless.tsを修正します。

  • AppSyncの認証方法の変更
  • sampleAuthの関数の定義
import type { AWS } from "@serverless/typescript";

const serverlessConfiguration: AWS = {
  service: "serverless-appsync-lambda-test",
  frameworkVersion: "2",
  custom: {
    webpack: {
      webpackConfig: "./webpack.config.js",
      includeModules: true,
    },
    appSync: {
      name: "appsync-sample-${opt:stage}", 
-      authenticationType: "API_KEY",
+      authenticationType: "AWS_LAMBDA",
schema: "./graphql/schema.graphql", 
-      apiKeys: [
-        {
-          name: "test-api-key",
-          description: "AppSync test",
-          expiresAfter: "30d",
-        },
-      ],
+      lambdaAuthorizerConfig: {
+        functionName: "sampleAuth",
+      },
      defaultMappingTemplates: {
        request: false,
        response: false,
      },
      mappingTemplates: [
        // queryとdataSourceを結びつける部分
        {
          dataSource: "sample",
          type: "Query",
          field: "sample",
        },
      ],
      dataSources: [
        // lambdaをdataSourceに設定する部分。この設定をすることでAppSyncからlambdaを呼び出せる
        {
          type: "AWS_LAMBDA",
          name: "sample",
          config: {
            functionName: "sample",
          },
        },
      ],
    },
    "appsync-simulator": {
      location: ".webpack/service",
      apiKey: "da2-fakeApiId123456",
      watch: false,
    },
  },
  plugins: [
    "serverless-webpack",
    "serverless-appsync-simulator",
    "serverless-appsync-plugin",
    "serverless-offline",
  ],
  provider: {
    name: "aws",
    runtime: "nodejs14.x",
    stage: '${opt:stage, "local"}',
    region: "ap-northeast-1",
    environment: {
      AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1",
    },
    lambdaHashingVersion: "20201221",
  },
  functions: {
    sample: {
      handler: "src/handler.sample",
    },
+    sampleAuth: {
+      handler: "src/handler.sampleAuth",
+    },
  },
};

module.exports = serverlessConfiguration;

実行

開発環境の起動

まずはofflineで起動して、http://localhost:20002にアクセスします。

npx serverless offline start --stage local

何も表示されません。。
GrapiQL

詳細を調べていきます。
offlineの起動では、serverless-appsync-simulatorが動いています。
serverless-appsync-simulatorは中身を見てみると、ほぼ、amplify-appsync-simulatorを実行しているだけになります。

なので、原因は以下のどちらかになりそうです。

  • serverless-appsync-simulatorの利用しているamplify-appsync-simulatorが古い
  • amplify-appsync-simulatorが対応していない

amplify-appsync-simulatorを見ていたら以下のissueがありました。
https://github.com/aws-amplify/amplify-cli/issues/7963

まだ対応されていないようです。残念ですが、対応されるのを待ちましょう。

AWS上での起動

AWSにデプロイして動作を確認してみます。

npx serverless deploy --stage dev

AppSyncのコンソールから実行してみました。
正しくデプロイできていることがわかります。

念のため、CloudWatch logの情報も見てみます。
ちゃんと実行されていることがわかります(※一部情報はxxxでマスクしています)。

2021-11-08T03:31:14.762Z	81eb0e5f-9440-41ca-b9a3-b6e84142b1f0	INFO	event > {
    "authorizationToken": "xxx",
    "requestContext": {
        "apiId": "xxx",
        "accountId": "xxx",
        "requestId": "xxx-9fab-42b3-b89e-929f4420c906",
        "queryString": "query MyQuery {\n  sample\n}\n",
        "operationName": "MyQuery",
        "variables": {}
    }
}

Discussion