🐡

k8s 環境で postgresql するなら pgproxy が便利

2023/12/11に公開

はじめに

kubernetes 環境で postgresql のコンテナを建てたり、kubernetes クラスタが存在する VPN に postgresql インスタンスを起動する場合、kubernetes の外から postgresql サーバにアクセスする事ができません。モチベーションとしては自分の端末から kubernetes VPN 内にいる postgresql サーバへ psql で接続したいのです。その為にインターネットに穴を開けたくない。

psql が入ったコンテナを追加する... そうじゃない!

失敗した作戦1

コンテナ環境に socat が入った ubuntu コンテナを建て、postgresql へのプロキシを作成、そのコンテナへ kubectl port-forward する作戦です。

$ socat tcp-listen:5432,reuseaddr,fork tcp-connect:<postgresqlのIP>:5432

残念ながらこのプロキシは接続元 IP が自端末となってしまいます。postgresql はデフォルトでは pg_hba.conf で決められたネットワークの外部からの接続は trust になっていないため、結果として接続できませんでした。

あともし上手く行ったとしても、socat を起動して kubernetes port-forward を起動するのは面倒すぎる。

失敗した作戦2

ならばと今度は kubernetes クラスタ内に tailscale を入れ、サブネットルータ化し、postgresql サーバに直接アクセスしてみました。

tailscale でサブネットルータを作るには tailscale のリポジトリ内に含まれる docs/k8s を使います。

https://tailscale.com/kb/1185/kubernetes/

先に secret を作っておきます。

apiVersion: v1
kind: Secret
metadata:
  name: tailscale-auth
stringData:
  TS_AUTHKEY: tskey-0123456789abcdef

TS_AUTHKEY は tailscale の設定画面から払い出して下さい。

そして Makefile を使って pod をデプロイします。

$ make subnet-router TS_ACCEPT_DNS=true TS_KUBE_SECRET=tailscale-auth TS_ROUTES=10.0.10.0/24,... | kubectl apply -f -

TS_ROUTS にはアクセスしたいネットワークをカンマ区切りで列挙します。これを使うと自端末からクラスタ内の IP にアクセスしてとても便利です。

これはこれで便利になったのですが、この場合でも接続元 IP が tailnet の IP になってしまうため作戦1と同じエラーになってしまいました。

成功した作戦

そこで紹介したいのが pgproxy を使う方法です。pgproxy は tailscale 社が提供している tailnet を介した postgresql 向けプロキシです。

pgproxy を使うには、kubernetes クラスタ内に tailscale を実行できるコンテナを建てる必要があります。作戦2を実行したのであれば、それを使ってもいいです。
※ 実際には tun kernel module を使えるサーバであれば良いです

僕の場合は作戦2でデプロイした pod を使いました。subnet-router に /bin/sh で入り、以下を実行します。

$ TS_AUTHKEY=tskey-auth-XXXXXXXXXXXXXXXXXXXX ./pgproxy --hostname postgresql-server:5432 --upstream-addr <postgresql サーバのIP>:5432  --upstream-ca-file /tmp/certs.pub  --state-dir state

※ certs.pub はサーバ証明書です。

ここで --hostname で指定するホスト名は 実際に存在しないホスト名 を設定してください。このコマンドを実行したタイミングで pgproxy が tailscale に 新しいマシン名 postgresql-server を登録 してくれます。

あとはそのマシンに対して psql を実行すればよいのです。

$ psql -h postgresql-server -W postgres

この方法だといちいち socat や port-forward を実行する面倒さもありません。

さらにこの方法を使うと kubernetes クラスタ内のアプリケーションが、tailscale ネットワーク内にいる、別ネットワークの postgresql サーバを使う事もできるのです。

おわりに

kubernetes クラスタにサブネットルータを導入し、さらに pgproxy を使って直接 postgresql サーバにアクセスできる様にしました。

世の中には postgresql サーバにアクセスする為にインターネットに口を開けてしまっているサーバが沢山あるらしいです。

https://innerjoin.bit.io/the-majority-of-postgresql-servers-on-the-internet-are-insecure-f1e5ea4b3da3

この記事内でも書いてある様に、tailscale や pgproxy を使って安全に保っておく必要があります。

Discussion