HerokuでNode.jsのアプリからPostgreSQLに接続できない時の対処

N予備校 【2020年度】プログラミング入門 Webアプリ
[第4章24節 【サービス開発9】セキュリティ対策と公開]

Herokuの設定で詰まったので解決した手順を記載。


Database / GitHubのOAuthなどの設定を終えてHerokuのアプリを起動し、ログインをしようとすると下記のエラーが発生

```
2021-02-21T03:05:26.710859+00:00 app[web.1]: Unhandled rejection SequelizeConnectionError: no pg_hba.conf entry for host "XX.XXX.XXX.XXX", user "xxxxxxxxxx", database "xxxxxxxxxxxx", SSL off
2021-02-21T03:05:26.710870+00:00 app[web.1]: at connection.connect.err (/app/node_modules/sequelize/lib/dialects/postgres/connection-manager.js:182:24)
2021-02-21T03:05:26.710870+00:00 app[web.1]: at Connection.connectingErrorHandler (/app/node_modules/pg/lib/client.js:194:14)
2021-02-21T03:05:26.710871+00:00 app[web.1]: at Connection.emit (events.js:198:13)
2021-02-21T03:05:26.710872+00:00 app[web.1]: at Socket.<anonymous> (/app/node_modules/pg/lib/connection.js:134:12)
2021-02-21T03:05:26.710872+00:00 app[web.1]: at Socket.emit (events.js:198:13)
2021-02-21T03:05:26.710872+00:00 app[web.1]: at addChunk (_stream_readable.js:288:12)
2021-02-21T03:05:26.710873+00:00 app[web.1]: at readableAddChunk (_stream_readable.js:269:11)
2021-02-21T03:05:26.710874+00:00 app[web.1]: at Socket.Readable.push (_stream_readable.js:224:10)
2021-02-21T03:05:26.710874+00:00 app[web.1]: at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
2021-02-21T03:05:56.475031+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/auth/github/callback?code=025f7e4e57093209889a" host=limitless-lowlands-54630.herokuapp.com request_id=31dc51eb-fd89-48fb-9155-a08b997709de fwd="153.207.171.208" dyno=web.1 connect=1ms service=30001ms status=503 bytes=0 protocol=https
```

・アプリからDB接続ができない (pg_hba.confの設定が足りない？)
・GitHubの認証がタイムアウトする (一つ前のDB接続エラー起因かはこの時点では不明)

エラーメッセージと pg_hba.conf、Herokuでぐぐってみたところ、解決方法としてHerokuの環境変数でDB接続をSSL化するか、node-jsのソース側でこのエラー制御を無視することができるようでした。

環境変数の追加が簡単そうだったので、方法１で対処しました。

##【方法１】
参考にした記事
https://qiita.com/hiro93n/items/fe015ce9517f139edbeb

Herokuに環境変数を設定する

```
heroku config:set PGSSLMODE=require
```

環境変数を更新したらHerokuが再起動して接続できるようになり、GitHub認証のタイムアウトエラーも解消しました。

```
2021-02-21T03:14:46.096182+00:00 app[api]: Release v11 created by user xxxxxxxxxx
2021-02-21T03:14:46.096182+00:00 app[api]: Set PGSSLMODE config vars by user xxxxxxxxxx
2021-02-21T03:14:46.573285+00:00 heroku[web.1]: Restarting
2021-02-21T03:14:46.590224+00:00 heroku[web.1]: State changed from up to starting
2021-02-21T03:14:48.006684+00:00 heroku[web.1]: Stopping all processes with SIGTERM
2021-02-21T03:14:48.223861+00:00 heroku[web.1]: Process exited with status 143
2021-02-21T03:14:50.316993+00:00 heroku[web.1]: Starting process with command `npm start`
```

Warningの中に、node-jsが理由を説明しているログがありました。

```
2021-02-21T03:14:53.846841+00:00 app[web.1]: (node:21) DeprecationWarning: 
Implicit disabling of certificate verification is deprecated and will be removed in pg 8. 
Specify `rejectUnauthorized: true` to require a valid CA or `rejectUnauthorized: false`
 to explicitly opt out of MITM protection.
```
暗黙的な証明書検証の無効化は非推奨となっていますので、pg 8で削除されます。rejectUnauthorized: true で証明書の検証をしているものをrejectUnauthorized: falseと指定することで、明示的に中間者攻撃防御を解除してください。


##【方法２】
Herokuの公式ドキュメント[Heroku Posgres]
https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-node-js

先ほどの理由からPosgreのDB接続用のインスタンスを生成するときに、ssl証明書検証の設定をfalseに明示的に設定する。

```
const client = new Client({
  connectionString: process.env.DATABASE_URL,
  ssl: {
    rejectUnauthorized: false
  }
});
```

今回は方法１で接続できましたが、方法２も公式ドキュメントの情報なので問題なく解決できそうです。

もし４章の最後の節で詰まってる方がいましたらご参考まで。