[Heroku] Private Space 内の Postgres へアクセスするには

本日 [Heroku Advent Calendar 2019](https://qiita.com/advent-calendar/2019/heroku) 23日目、昨日は[@syui](https://qiita.com/syui)さんのMastodonネタ「[Herokuで立てる分散SNS](https://syui.cf/blog/post/2019/12/22/heroku-sns/)」で、明日は[@kimihom](https://qiita.com/kimihom)さんのネタです。今から楽しみですね!!

そして、12月23日といえば、かしゆかの誕生日です(∩´∀｀)∩おめでとう、ゆかちゃん!!1

昨年までは祝日だったので、今年からは有給休暇を取得して、お休みすることにしたよゆかちゃん!!!1111あああああああああああああああああああああああああああああああ

# Heroku Private Postgres へのアクセスは大変

かしゆかに会うことが難しいように、Heroku Private Spaces 内に構成された Heroku Postgres を始めとするデータサービスへのアクセスは、実は難しいのです。かしゆか同様、小悪魔なのかな、そうなのかな、と思わせつつもこれは、セキュリティの世の流れだったりします。儚い。

特に、Shield Private Spaces になろうものなら、`heroku pg:psql` コマンドを使ったところでアクセスができません。ご覧ください、この無情なるtime out。

```bash
$ heroku pg:psql -a shield-heroku-app
--> Connecting to postgresql-rugged-xxxxx
psql: error: could not connect to server: could not connect to server: Operation timed out
        Is the server running on host "ec2-xx-178-xx-xx.ap-northeast-1.compute.amazonaws.com" (xx.178.xx.xx) and accepting
        TCP/IP connections on port 5432?
```
同じ Shield Private Space 内にある Heroku Dyno 以外からのアクセスは完全にできません。[制限](https://devcenter.heroku.com/articles/heroku-postgres-and-private-spaces#shield-tier-plans)を多く準備することで、より安全なデータサービスを提供するということですね。理解します。

そんな、かしゆかのように大事に扱われている Heroku Postgres に対して、強引に迫ろうというのが今日の企画です。わいもかしゆかに会いたい。

さて、Heroku Private Spaces 内の Heroku Postgres へアクセスするには、どのような方法があるのでしょうか。

# Private Space 内の Postgres へのアクセスを許可する 3つの方法と特徴

3つありますが、全てにおいて扱い方も設定の仕方も異なります。

1. [Trusted IP Ranges for data services](https://devcenter.heroku.com/articles/private-spaces#trusted-ip-ranges-for-data-services)
2. [Heroku Postgres via PrivateLink](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink)
3. [Heroku Postgres from External Resource via MTLS](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls)

 | Trusted IP Ranges | PrivateLink | MTLS
---+---+---+---
概要 | アクセス元のIPアドレスホワイトリスト | Amazon PrivateLink で接続 | アクセス元からTLS証明書で接続
Private Spaceへの接続 | ○ | ○ | ○
Shield PS への接続 | ☓ | ○ | ○
アクセス元 | anywhere | Amazon VPC only | anywhere
設定方法 | [チケット](https://devcenter.heroku.com/articles/private-spaces#trusted-ip-ranges-for-data-services) | 主に [cli](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink) | 主に [cli](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls)
サポート | βサービス | 本番提供 | 本番提供

ご覧いただくとわかるように、本番として利用する場合であれば、`PrivateLink` や `MTLS` 方式を採用するほうが吉です。特に、すでに `Amazon VPC` を利用していて、そこから接続するような場合は `PrivateLink`を採用することが良いと「個人的に」おすすめします。

## 設定手順

具体的な設定手順は、リンク先で懇切丁寧に述べられているので、いくら英語だとはいえコマンドと画面がずらーっと並んでいて、そのままやればいいだけですので心配しなくても良いです。気が向いたら、翻訳します。

ここでは、設定の流れだけ追います。

### [Trusted IP Ranges for data services](https://devcenter.heroku.com/articles/private-spaces#trusted-ip-ranges-for-data-services)

[Heroku Support](https://help.heroku.com/) から、「なぜ、我々は Trusted IP Rangesを使ってまで、外部からアクセスをしなければならないか」という熱い思いを添えてチケットを上げてください。いや、熱くたぎる想いは邪魔なので、理由だけ添えてチケットを上げてください。ごめんなさい。

現時点では `PrivateLink` や `MTLS` といったセキュアな接続方法が提示されているので、それが利用できないケースで致し方ないケースにおいてのみ、こちらのサービスを利用するような選択が望ましいでしょう。BIツールの接続などは、このパターンに該当するかもしれません。

### [Heroku Postgres via PrivateLink](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink)

![1558486064-private-links-multi-vpc-diagram@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/144ea05e-5318-f865-a704-d4cdac2d1916.png)

1. Heroku Private Space 側に PrivateLink の[エンドポイントを作成](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink#provisioning-the-heroku-endpoint)
2. 作成されたエンドポイントへ [Amazon VPC 側から接続](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink#provisioning-the-amazon-vpc-endpoint)

だけです。実際に試してみたら、ほんとにあっさりです。なお、Private Space の場合であれば、Heroku Postgres のダッシュボードから設定できそうな雰囲気があります。ここで`Enable`したらいけそうですよね。

<img width="899" alt="Screen Shot 2019-12-23 at 7.41.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/789ea6d7-b47c-7e9d-e535-0a7862a544b7.png">

なので `Enable` ボタンをおもむろに押してみます。ここに AWS の Account ID を入れたらできそうですが、何も起きません。残念ながら諦めるほかなさそうです。

<img width="347" alt="Screen Shot 2019-12-23 at 7.41.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/1b7dbde8-9250-a539-89ec-46899c60681d.png">

ただ、全て設定された後に、こんな感じで構成情報を確認できるのはありがたいですよ。いいですね、この小悪魔感。かしゆかの誕生日にもってこいです。

<img width="904" alt="Screen Shot 2019-12-23 at 8.11.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/95403125-6988-e440-b9fc-ad4174e73679.png">

とりあえず、最後にできあがった `Endpoint URL` に対して Postgres として接続してあげれば、どのような方法でもアクセスできます。`psql`コマンドでも、このように。

```bash
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-1032-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Dec 22 23:09:03 UTC 2019

  System load:  0.31              Processes:           93
  Usage of /:   29.7% of 7.69GB   Users logged in:     0
  Memory usage: 18%               IP address for ens5: 172.30.0.12
  Swap usage:   0%

 * Overheard at KubeCon: "microk8s.status just blew my mind".

     https://microk8s.io/docs/commands#microk8s.status

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

2 packages can be updated.
0 updates are security updates.


*** System restart required ***
Last login: Sun Dec 22 23:02:30 2019 from xx.xxx.xxx.xxx

ubuntu@ip-172-xx-xx-xx:~$ psql postgres://u6o59alpve3v94:xxxxxxxxxxx
ap-northeast-1.vpce.amazonaws.com:5432/
psql (10.11 (Ubuntu 10.11-1.pgdg18.04+1))
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

d87h4qogjal0of=>
```

### [Heroku Postgres from External Resource via MTLS](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls)

![1565978646-Shield-Postgres-Access.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/c96d760b-7e55-7550-de79-44724cdc7087.png)

最後。最近発表されたサービスですね。IPアドレスホワイトリストを作って、そこからしかアクセスさせないのは[Trusted IP Ranges for data services](https://devcenter.heroku.com/articles/private-spaces#trusted-ip-ranges-for-data-services)と同じです。ただ、それだけではありません。Heroku Postgres 側から提供される証明書を使わないとアクセスすることができないという仕組みになります。

アクセス元を限定しないので、PrivateLink 方式よりも選択の幅が広がります。また、Shield Postgres へも接続ができるので、手元のDB管理端末から`psql`コマンドで接続することも可能です。とは言え、穴を開けての接続サービスになりますから、IPアドレスホワイトリストの作成は慎重に行いましょう。

1. [MTLSアクセスの許可とホワイトリストの作成](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls#configuring-mutual-tls-and-whitelisting-your-ip)
2. [証明書のダウンロード](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls#setting-client-side-certificates)

こちらも手順としてはこれだけなんですが、1 → 2 のとこで時間がかかります。なんでか分かりませんが、証明書を作成するのに、やたら時間がかかります。どんだけ時間がかかるのかは謎ですが、そのうちできとります。小悪魔感満載ですね。かしゆかの日にぴったりです。

さて、これで完成すると、手元のPCから `psql`コマンドが使えます。

```bash

psql postgres://u6o59alpve3v94:xxxxxxxx
psql (12.1, server 10.11 (Ubuntu 10.11-1.pgdg16.04+1))
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

d87h4qogjal0of=>
```

`heroku pg:psql` コマンドの場合、オーバーヘッドがありますが、`psql`単独だと接続も利用開始も早いのが特徴です。かと言って、そのためだけに接続させてよいのかどうかはコンプライアンス含めて検討が必要でしょう。

# まとめ

そもそもは、まず Heroku Postgres への Direct Connection が必要かどうかをご検討ください。そのうえで、本当に業務上必要であれば、これらのサービスを利用しましょう。Shield Private Spaces でも利用できるとこは、一つのポイントですね。

 | Trusted IP Ranges | PrivateLink | MTLS
---+---+---+---
概要 | アクセス元のIPアドレスホワイトリスト | Amazon PrivateLink で接続 | アクセス元からTLS証明書で接続
Private Spaceへの接続 | ○ | ○ | ○
Shield PS への接続 | ☓ | ○ | ○
アクセス元 | anywhere | Amazon VPC only | anywhere
設定方法 | [チケット](https://devcenter.heroku.com/articles/private-spaces#trusted-ip-ranges-for-data-services) | 主に [cli](https://devcenter.heroku.com/articles/heroku-postgres-via-privatelink) | 主に [cli](https://devcenter.heroku.com/articles/heroku-postgres-via-mtls)
サポート | βサービス | 本番提供 | 本番提供