この記事は
postgreSQLにWebからアクセスするためのAPIを提供するpostgRESTをつかおうとしたときに、認証周りで失敗した話です。
- postgREST http://postgrest.org/en/v5.1/index.html
失敗の経緯
- 提供されているdocker-composeで動かして、とりあえずうまく行っていた
- そろそろ認証をかけたいなと思ったときに、色々な勘違いにより失敗した。
はじめに
ちょっとした経緯で、またWebアプリを書くことになりました。
データベースに格納されたデータを参照して、意思決定をしたいということで、supersetやらmetabaseを使えばよさそうなんだけれども、ちょっとインタラクションをこだわりたいみたいな話があり、やむなくBootstrapベースでフルスクラッチすることに。
(((要求抽出が進んで、これってMetabaseでよくね?となってきたのですが、それはおいておいて…)))
今回は認証周りで色々ハマったので、忘備録として軽くメモ書きします。
結論を早く知りたい人は、一番下にまとめてあるので、それを参照ください。
環境 (バージョンは割愛 ちょっと古いです)
- CentOS
- docker
- docker-compose
- postgres (docker container)
やったこと
機能の概要は分かったので、とりあえず公開されているdocker-compose.ymlを少し改変して動作させる
version: '3'
services:
server:
image: postgrest/postgrest
# ports: #ポート3000は公開せずに別のnginxコンテナでリバースプロキシする
# - "3000:3000"
links:
- db:db
environment:
PGRST_DB_URI: postgres://app_user:password@db:5432/app_db
PGRST_DB_SCHEMA: public
PGRST_DB_ANON_ROLE: app_user #In production this role should not be the same as the one used for the connection
depends_on:
- db
db:
image: postgres
ports:
- "5432:5432"
environment:
POSTGRES_DB: app_db
POSTGRES_USER: app_user
POSTGRES_PASSWORD: password
# Uncomment this if you want to persist the data.
# volumes:
# - "./pgdata:/var/lib/postgresql/data"
このコンテナを立ち上げて、nginxでproxy設定を書いてやると、なるほど、いいじゃないか!
ということで、採用。
認証について知るために、あとからチュートリアルをやる
postgRESTはチュートリアルが2段階で用意されており、Tutorial 0(http://postgrest.org/en/v5.1/tutorials/tut0.html) は主にインストールの話、Tutorial 1は認証の話です。
自分は既にdockerでインストール済なので、Tutorial 1から始めました。
tutorial.conf?
Step 1でユーザを作って、Step 2で秘密鍵を作るのですが、その秘密鍵をtutorial.conf
に記述せよと。dockerをやっている範囲ではそんなもん書いていないので、ここで一度ハマる。
とはいえ、どうせ環境変数で設定するんだろうとタカをくくり、
docker-compose exec server bash
***# env
とやって環境変数を確認。案の定、PGRST_JWT_SECRET
というエントリがあったので、適当なパスワード(password
的な)のを登録してdocker-compose up -d server
でサーバを再起動。
まったく認証が動作している気配がない。
JWTの設定をしてもapp_db
の内容が全部参照できてしまう。これはどうしたことか、、、と思案するなかで、ここで初めてTutorial 0に戻る。すると
db-uri = "postgres://postgres:mysecretpassword@localhost/postgres"
db-schema = "api"
db-anon-role = "web_anon"
docker-compose.yml
では db-anon-role
が同じスーパユーザに設定されているために、認証に失敗してAnonymousで入った結果、すべて参照できるようになっていたとわかる。
PGRST_DB_ANON_ROLE
を存在しないユーザに設定し、想定通り403が返ってくるようになった。
認証が通らない
ここで、jwt.ioで認証トークンを作成して、curlのヘッダに登録すると、次は401で認証エラーが返ってくるようになった。
良く調べると(というか、ちゃんと書いてあるんだけれど)秘密鍵は32文字以上必要とのこと。
というわけで、
秘密鍵を32文字以上にしたら動くようになった。
まとめ
docker-composeでpostgRESTを動かした後はこの手順で設定すればよい。
- Anonymous Roleを設定する
-
PGRST_DB_ANON_ROLE
をスーパユーザ以外に設定する - 接続先のDBにロールを作成し、Anonymous用の権限を付ける
-
- 秘密鍵を設定する
-
PGRST_JWT_SECRET
の環境変数エントリを設定し、32文字以上の秘密鍵を平文で書く - JWT.ioにアクセスし、Payloadに
{"role": アクセスしていいユーザ}
を設定する- 何も考えないと
app_user
になるが、スーパユーザはなぁ、と思う人はもう一人別のロールを作って権限設定をする。
- 何も考えないと
- Signatureの「ここだよ」と書いてあるところに秘密鍵を入力する
-
ついでに分かったこと
-
postgres/postgres
dockerイメージは/etc/postgrest.conf
を参照している。環境変数でなく、confファイルを直接参照させたい人は、このファイルをホストからコントロールできるようにすればいい