【AWS】API GatewayのCustomAuthorizerを設定する

## 概要

- LambdaなどをAPI Gateway経由で公開することはよくあると思います
- ですが公開したエンドポイントが誰でも叩けると困るケースもあります
- そんな時にAPI GatewayのCustom Authorizerを使うと簡単に認証機能を付与できます
- 今回はServerlessFrameworkを使った手順を紹介します

## 手順

### 雛形生成

- ServerlessFrameworkで雛形を作るところからいきます

```zsh
mkdir custom-auth-sample
cd custom-auth-sample
sls create -t aws-nodejs-typescript
npm i
```

- 一式作成できました

```
tree -I node_modules
.
├── handler.ts
├── package-lock.json
├── package.json
├── serverless.yml
├── tsconfig.json
├── vscode
│   └── launch.json
└── webpack.config.js
```

### Hello関数の動作確認

- デフォルトでHello関数があるのでそれを確認しておきます
    - Hello関数を認証突破しないと叩けないようにする流れで進めていきます
- handler.tsではhello関数は`message`などをreturnするだけの処理として定義してあります

```ts:handler.ts
// handler.ts抜粋
export const hello: APIGatewayProxyHandler = async (event, _context) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!',
      input: event,
    }, null, 2),
  };
}
```

- serverless.ymlでhello関数には`GET:/hello`でアクセスできるように定義してあります

```yml:serverless.yml
# serverless.yml抜粋

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          method: get
          path: hello
```

- デプロイしましょう

```zsh
sls deploy
```

<img width="740" alt="スクリーンショット 2020-06-02 1.31.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/cf2c5a94-3923-27f4-9e91-e057a1f675d7.png">

- ログに出てくるURLにアクセスするmessageが返ってきます

<img width="1000" alt="スクリーンショット 2020-06-02 1.32.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c5c96238-4509-885d-1cd2-34b2186f3878.png">

### Auth関数の作成

- ユーザから送信されたトークンが正しいかどうかチェックする関数を作成します
- handler.tsの一番下に以下の内容を追記してください
    - headerのAuthorizationにセットされた値と、事前に定義しておいたキーが一致してるかチェックしています
    - 一致した場合は後続の処理を実行する権限が付与され実行されます

```ts:handler.ts
// 省略

export const auth: CustomAuthorizerHandler = (event, context) => {
  const { authorizationToken } = event;
  if (authorizationToken === process.env.AUTH_KEY) {
    const policy = {
      principalId: 'user',
      policyDocument: {
        Version: '2012-10-17',
        Statement: [
          {
            Action: 'execute-api:Invoke',
            Effect: 'Allow',
            Resource: event.methodArn,
          },
        ],
      },
    };
    context.succeed(policy);
  } else {
    context.fail('Unauthorized');
  }
};
```

- serverless.ymlにCustomAuthorizerとして登録する設定をします
    - 全量載せていませんがコメントで書いている部分を追記しているだけです
    - AUTH_KEYを直接埋め込むのが嫌なケースはdotenvなど使うといいでしょう
        - 参考: [ServerlessFrameworkでdotenvを使う](https://qiita.com/ozaki25/items/c855c3c7bcb45515539f)

```yml:serverless.yml
# 省略
provider:
  # 省略
  environment:
    AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1
    AUTH_KEY: password@12345 # キーを環境変数として設定

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          method: get
          path: hello
          authorizer: authorizerFunc # CustomAuthorizerが適用されるように設定
  # 追加したLambda関数を登録
  authorizerFunc:
    handler: handler.auth
```

- デプロイしましょう

```zsh
sls deploy
```

- デプロイできたら再びHello関数にアクセスしてみましょう

<img width="871" alt="スクリーンショット 2020-06-02 1.42.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/2c00a15c-89c7-7aab-f1a8-385ae2eb0d43.png">

- 設定が適用されていれば401で弾かれているはずです
- headerのAuthorizationにキーを設定して再度アクセスしてみます

<img width="913" alt="スクリーンショット 2020-06-02 1.44.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/19d29e8f-528a-4df8-ba92-c00af67a5347.png">

- キーが正しいのでちゃんとアクセスできました！簡単ですね！

## まとめ

- 簡単なCustomAuthorizerの設定はServerlessFrameworkを使うと簡単に実現することができました！