ポートフォリオ「Hubpin」を開発中の著者が、Supabaseのservice role(RLS=行レベルセキュリティをバイパスできる特権ロール)の権限について、誤解と訂正を重ねた実体験を記しています。当初は「service roleはGRANTもRLSも通らない」と考えていましたが、次に「RLSはバイパスするがGRANTは効く。ただしSupabaseの既定で権限が配られている」と修正しました。
しかし実際にPostgreSQLのpg_classテーブルのrelaclカラムを確認したところ、service_roleに付与されていたのはD(TRUNCATE)・x(REFERENCES)・t(TRIGGER)・m(MAINTAIN)のみで、a(INSERT)・r(SELECT)・w(UPDATE)・d(DELETE)はすべて欠落していたことが判明しました。問題は本番環境でCronジョブが初めて走った際に発覚し、開発環境ではanonロールとauthenticatedロールしか使っていなかったため気づけなかったといいます。
著者は「RLSのバイパスはロール属性、GRANTは権限。別の関門でした」と結論づけ、grant select, insert, delete on public.feed_entries to service_role; というSQLで権限を付与したと述べています。また、proaclがNULLの場合はデフォルトのままであることを意味し権限なしではない点や、PUBLIC権限からrevokeするとservice roleも巻き込まれる点にも注意を促しています。
出典が伝えている要点
- 著者はポートフォリオ「Hubpin」を開発している
- 著者は当初「service roleはGRANTもRLSも通らない」と考えていた
- 著者は次に「service roleはRLSをバイパスするがGRANTは効く。ただしSupabaseの既定で権限が配られている」と考えを修正した
- 著者はPostgreSQLのpg_classテーブルのrelaclカラムを確認し実測した
- 実測の結果、service_roleにはD(TRUNCATE)、x(REFERENCES)、t(TRIGGER)、m(MAINTAIN)の権限のみが付与されていた
- 実測の結果、service_roleにはa(INSERT)、r(SELECT)、w(UPDATE)、d(DELETE)の権限がすべて欠落していた
- 著者はRLSのバイパスはロール属性によるもの、GRANTは権限によるものであり、両者は別の関門であると結論づけた
- 著者は「grant select, insert, delete on public.feed_entries to service_role;」というSQL文を実装して権限を付与した
- 著者はproaclがNULLの場合、それは権限がないことを意味するのではなく、デフォルトのままであることを意味すると指摘している
- 著者はPUBLIC権限からrevokeするとservice roleも巻き込まれる問題があると報告している
- 権限不足の問題は本番環境でCronジョブが初めて実行された際に発覚した
- 開発環境ではanonロールとauthenticatedロールしか使用しておらず、service roleの権限不足は検出されなかった
原文より
service_roleにあるのはDxtmだけ。arwdが1つも入っていません
RLSのバイパスはロール属性、GRANTは権限。別の関門でした
発覚するのは本番でCronが初めて走ったときだった
出典: zenn.dev