CloudFront + API Gateway + Lambda の環境でうまくいかない場合のレスポンスとその原因

この記事は、[会社のブログ](https://doruby.jp/users/nakamatsu/entries/CludFront---API-Gateway---Lambda-%E3%81%AE%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%86%E3%81%BE%E3%81%8F%E3%81%84%E3%81%8B%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AE%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%A8%E3%81%9D%E3%81%AE%E5%8E%9F%E5%9B%A0)[^1]とのクロスポストです。 

※随時追加予定

API Gateway のエラー時のレスポンスのメッセージは必ずしもその原因と直結するような内容となっていないことが多々あり、原因の特定に時間がかかりがちなのでメモっておく。

「レスポンス」の内容は、`curl -v`でのリクエストに対するレスポンスを多少加工して掲載している。

## 401 'Unauthorized'

### レスポンス

```
< HTTP/2 401
< date: Wed, 22 May 2019 08:43:33 GMT
< content-type: application/json
< content-length: 26
< x-amzn-requestid: xxxxxxxxxxxxxxxx
< x-amzn-errortype: UnauthorizedException
< x-amz-apigw-id: xxxxxxxxxxxxxxxxxxx

{"message":"Unauthorized"}
```

### 原因

* カスタムオーソライザに必要な情報（特定のリクエストヘッダ等）がリクエストに含まれていない
    * 例えば `Cookie` の`session_id`を使ってAPIへのアクセスを認可するオーソライザを設定している場合、`Cookie`ヘッダがリクエストに含まれていない場合に前述のリクエストが返ってくる


## 403 'Missing Authentication Token'

### レスポンス

```
< HTTP/2 403
< date: Wed, 22 May 2019 08:31:54 GMT
< content-type: application/json
< content-length: 42
< x-amzn-requestid: xxxxxxxxxxxxxxxxx
< x-amzn-errortype: MissingAuthenticationTokenException
< x-amz-apigw-id: xxxxxxxxxxxxxx

{"message":"Missing Authentication Token"}
```

### 原因

* API Gateway のエンドポイントのパスが間違っている
    * 例えば正しいエンドポイントのURLが以下であった場合
        * `https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/api/v1/{+proxy}`
    * 以下のように間違っている(`/api`が抜けている)と前述のようなレスポンスが返ってくる
        * `https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/v1/xxxxxx`


## 403 Forbidden

（コメントより）

> * API Mappings で Base Path を省略するとリソースにアクセスできなくなる不具合がある。
>
> [Amazon API Gateway を独自ドメインで利用する ｜ Developers.IO](https://dev.classmethod.jp/cloud/aws/api-gateway-with-custom-domain/)

私が経験したものではなかったですが、参考になります。 @wcm7432 さん、ありがとうございました。

## 403 'User is not authorized to access this resource with an explicit deny'

### レスポンス

```
< HTTP/1.1 403 Forbidden
< Date: Wed, 22 May 2019 08:56:27 GMT
< Content-Type: application/json
< Content-Length: 82
< Connection: keep-alive
< x-amzn-RequestId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
< x-amzn-ErrorType: AccessDeniedException
< x-amz-apigw-id: xxxxxxxxxxx

{"Message":"User is not authorized to access this resource with an explicit deny"}
```

### 原因

* カスタムオーソライザから `DENY` のポリシー文書が返却された場合に返ってくるレスポンス
    * カスタムオーソライザの呼び出し自体には成功しているので、大体のケースにおいては正常動作と言える（正常でない場合はカスタムオーソライザをデバッグすることになる）

## 503 (HTML形式で) 'ERROR: The request could not be satisfied'

### レスポンス

```html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>502 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
CloudFront attempted to establish a connection with the origin, but either the attempt failed or the origin closed the connection.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
```

### 原因

* CloudFrontのオリジン(API Gateway)に対して http でアクセスしている

   * CloudFront のオリジンの設定(Origin Protocol Policy)が HTTP Only のようになっていないか確認する
   * API Gateway は HTTPS しかサポートしていないので、 HTTPS Only とするべき

[^1]: 2022-01-09 現在、リンク先の企業には在籍していない。また、退職後にブログ記事の引っ越しがあったらしく記事の署名が別の人に書き換わっている模様....