Network Restrictions
supabaseが提供している postgres databaseに対して、psql
コマンドや psycopg2
(python) などのデータベースアダプタを使って接続することができます。
これはセキュリティホールになり得るため、接続元のIPアドレスを制限しておく必要があります。
supabase では Network Restrictions という機能があり、これを設定しておくことで上記のIP制限が実現可能です。
いざ設定してみる
まずは psqlを使って、何も設定しない状態でデータベースログインできることを確認します。
ダッシュボードの上部に常に「Connect」のボタンがあるので、これをクリックして接続用のパラメータを確認します。
以下が接続用のコマンドです。パスワードが要求されるので、プロジェクト作成時に設定したパスワードを打ち込むとインタラクティブシェルにログインできます。
psql -U postgres -h db.xxxxxxxxxxxxxxxx.supabase.co -p 5432 -d postgres
それでは Network Restictionsを設定してみましょう。
Network Restictionsは、左のドロワーの「Project Setting」→ 「Database」のページの下の方にあります。
Add restriction
のボタンをクリックすると、Add IPv4 restriction
と Add IPv6 restriction
が表示されます。
ここでは、接続を許可したいIPアドレスを登録します。
自社のIPv4はよく知ってるので、こちらを設定します。
これで設定は完了です。これで自社のIP外からの接続はできなくなるはず。
psqlのログインができなくなる
さきほどの psqlコマンド
psql -U postgres -h db.xxxxxxxxxxxxxxxx.supabase.co -p 5432 -d postgres
これを実行しても、ログインができません。少なくとも自社環境からは接続できるつもりで設定したのに、どこからも接続ができなくなってしまいました。
何が問題だったのでしょうか。
公式ドキュメントに立ち返る
Each Supabase project comes with configurable restrictions on the IP ranges that are allowed to connect to Postgres and its pooler ("your database"). These restrictions are enforced before traffic reaches your database. If a connection is not restricted by IP, it still needs to authenticate successfully with valid database credentials.
If direct connections to your database resolve to a IPv6 address, you need to add both IPv4 and IPv6 CIDRs to the list of allowed CIDRs. Network Restrictions will be applied to all database connection routes, whether pooled or direct. You will need to add both the IPv4 and IPv6 networks you want to allow. There are two exceptions: If you have been granted an extension on the IPv6 migration OR if you have purchased the IPv4 add-on, you need only add IPv4 CIDRs.
データベースへの直接接続が IPv6 アドレスに解決される場合、許可される CIDR のリストに IPv4 と IPv6 の両方の CIDR を追加する必要があります。
とあります。
psqlで接続先ホスト名をFQDNで指定していました。(db.xxxxxxxxxxxxxxxx.supabase.co
の部分)
nslookup
で名前解決してみます。
$ nslookup db.xxxxxxxxxxxxxx.supabase.co
Server: xxxxxxxxxxxxxxxxxxx
Address: xxxxxxxxxxxxxxxxxxx
Non-authoritative answer:
*** Can't find db.xxxxxxxxxxxxxx.supabase.co: No answer
IPv4がないようです。set type=AAAA をつけて IPv6を表示します。
$ nslookup
> set type=AAAA
> db.xxxxxxxxxxxxxxxx.supabase.co
Server: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
Address: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
Non-authoritative answer:
db.xxxxxxxxxxxxxxxxxx.co has AAAA address xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
IPv6が取得できました。
つまり何が起こったかというと、こういうことのようです。
- 接続パラメータに指定した
db.xxxxxxxxxxxxxxxx.supabase.co
にはIPv4が割り当てられていないため、名前解決の結果IPv6アドレスが指定された - postgresの接続プロトコルは、送信元アドレスにIPv6を指定して接続しに行く
- Network RestrictionsにはIPv4の許可アドレスしか設定されていないため、v6で来た接続リクエストはすべて拒否される
ならば 自社のIPv6を許可アドレスに加えてあげればOKでしょう。
自社のIPv6アドレスを確認し、Network Restrictionsの Add IPv6 restriction
にこちらを設定します。
psql -U postgres -h db.xxxxxxxxxxxxxxxx.supabase.co -p 5432 -d postgres
これが通るようになりました!
なぜIPv4がない?
Supabaseは postgresに対して3つの接続方式を用意しており、そのうち Direct connection
(先程のpsqlコマンドで指定したいた方式)はデフォルトで IPv4が設定されいないようです。
addonに課金すれば、使えるようになります。
下2つの Transaction pooler
, Session pooler
はIPv4が使えるようです。
永続的なコネクションを貼る Direct connection にIPv4を設定すると、IPアドレスを占有し続ける必要があるため、その分お金がかかるということのようです。(AWSのElastic IPアドレスも解放するまで課金されますね)
一方で Transaction / Session pooler は接続が一時的なものなので、名前解決先のIPv4がぼちぼち変わったとしても問題ないということなのでしょう。