Article
PostgreSQLのlo_compat_privilegesをoffに保つ理由と権限修正の手順
PostgreSQLで`lo_compat_privileges = on`にすると、ラージオブジェクトに対するPostgreSQL 9.0以降の主要な権限検査が無効になります。実効設定と所有者・ACLを調べ、設定でエラーを隠さず最小権限で直す流れを整理します。
Share
こはるの読みどころ
「エラーが消える」と「権限が正しくなる」は別物だね。互換設定を変える前に、どのロールが何を読む・書く・削除するべきかを整理してみよう!

PostgreSQLでpermission denied for large objectに出会うと、lo_compat_privilegesをonにして先へ進みたくなるかもしれません。実際、権限エラーが消えるケースはあります。
ただし、この設定は不足した権限を補うものではありません。PostgreSQL 9.0でラージオブジェクトへ導入された権限モデルを、8.4以前との互換動作へ戻すスイッチです。
では、引き継いだデータベースでonを見つけたとき、どこから調べれば安全にoffへ戻せるのでしょうか。設定の境界から、所有者ずれを直す手順まで順に見ていきます。
権限エラーを消す代わりにラージオブジェクトのACLを迂回する
PostgreSQL 18の互換性設定では、lo_compat_privilegesの既定値はoffです。onにすると、PostgreSQL 9.0で加わったラージオブジェクトの権限検査が無効になります。
具体的には、lo_open()で行う読み書きの検査と、それに依存するlo_get()、lo_put()、lo_read()、lo_truncate()などの処理が影響を受けます。lo_unlink()の所有者検査や、ラージオブジェクトに対するCOMMENTとSECURITY LABELの検査も迂回されます。
一方、すべての検査が消えるわけではありません。GRANT ... ON LARGE OBJECTの権限、ALTER LARGE OBJECT ... OWNER TOの所有者要件、サーバー側のlo_import()とlo_export()に必要な権限は別に残ります。公式資料も、この設定が無効にするのはPostgreSQL 9.0で挙動が変わった検査だけだと明記しています。
つまり、これは新しいCVEや特定バージョンだけの不具合ではなく、以前から存在する互換設定の注意点です。実際のリスクは、ラージオブジェクトを使っているか、どのロールが接続できるか、設定がどの範囲で有効かによって変わります。
PostgreSQL 9.0の所有者とACLが互換設定の境界を作った
2010年9月20日に公開されたPostgreSQL 9.0で、ラージオブジェクトごとの所有者とアクセス権限が導入されました。それ以前はラージオブジェクトに権限構造がなく、データベース内のユーザーが読み書きできるモデルでした。
現在のラージオブジェクト実装では、読み取りにSELECT、書き込みと切り詰めにUPDATEが必要です。削除、コメント、所有者変更は、所有者またはデータベースのスーパーユーザーに限定されます。
ラージオブジェクトの実体は通常のテーブル行とは別のオブジェクトとして管理され、所有者とACLはpg_largeobject_metadataに保存されます。このため、参照元テーブルへアクセスできても、ラージオブジェクト自体を作成したロールとアプリケーションの接続ロールが違えば、読み書きが拒否されることがあります。
移行ユーザーやETL用ロールでインポートし、アプリケーションは別ロールで読む構成が典型例です。ここで互換設定をonにすると症状は消えますが、所有者やACLのずれは残ったままになります。
実効値と設定元はアプリケーションの接続条件で特定する
最初に、アプリケーションと同じデータベース・ロールで実効値を見ます。SHOWは現在のセッションで解決された値を返します。
SHOW lo_compat_privileges;
設定ファイル由来か、データベース・ロール・セッションなど別の経路かを切り分けるには、pg_settingsのsourceを確認します。sourcefileとsourcelineは設定ファイル由来のときに手掛かりになりますが、閲覧ロールによってはNULLになります。
SELECT setting, source, sourcefile, sourceline
FROM pg_settings
WHERE name =
;
この設定を変更できるのは、スーパーユーザーまたは対象パラメーターのSET権限を持つロールです。パラメーター単位のSET権限はPostgreSQL 15で導入されたため、15以降では委譲先も棚卸し対象になります。
永続設定を変える前に、許可された検証セッションで一時的にoffへ戻し、実際のアプリケーション操作がどこで拒否されるかを観察できます。SET LOCALの効果はトランザクション内だけです。
BEGIN;
SET LOCAL lo_compat_privileges = off;
SHOW lo_compat_privileges;
ROLLBACK;
このSHOWとROLLBACKの間で、対象の読み書き処理を検証します。本番トラフィックのあるセッションで試すのではなく、ロールとデータを限定した検証環境で切り分けるのが安全です。
所有者ずれはpg_largeobject_metadataから最小権限で直す
実効値がonなら、次はラージオブジェクトの所有者とACLを一覧にします。lomownerはロールのOIDなので、pg_get_userbyid()で名前へ変換すると確認しやすくなります。
SELECT
oid,
pg_get_userbyid(lomowner) AS owner_name,
lomacl
FROM pg_largeobject_metadata
ORDER BY oid;
読み取りだけが必要なロールにはSELECT、書き込みや切り詰めも必要ならUPDATEを付与できます。GRANTの構文はラージオブジェクトごとにこの2種類を分けています。
GRANT SELECT ON LARGE OBJECT 12345 TO app_role;
GRANT UPDATE ON LARGE OBJECT 12345 TO app_role;
削除やライフサイクル管理までアプリケーションの責務なら、所有者の移管を検討します。ただし、ALTER LARGE OBJECTには現在の所有権と新しい所有ロールへ切り替えられる権限が必要です。
ALTER LARGE OBJECT 12345 OWNER TO app_role;
12345とapp_roleは例です。全件を一括変更する前に、参照元、期待する所有者、読み取り専用か書き込みも必要かを照合します。読み取りだけなら所有者を移すよりSELECTだけを付与する方が、権限の意図を狭く保てます。
vacuumloが止まるなら互換設定ではなく実行ロールを直す
vacuumloは、どのoid型またはlo型の列からも参照されていないラージオブジェクトを探して削除するユーティリティです。公式ドキュメントには、削除せず対象だけを表示する--dry-runも用意されています。
vacuumlo --dry-run --username=maintenance_role database_name
実際の削除ではlo_unlink()が呼ばれるため、実行ロールが対象オブジェクトの所有者でなければ処理が止まります。このエラーをlo_compat_privileges = onで避けるのではなく、vacuumloを適切な所有者またはスーパーユーザーで実行し、まずdry runの対象をレビューします。
ここでも設定を緩めるより、保守ジョブの責務と実行ロールを一致させる方が原因を説明できます。次回の実行でも同じ権限モデルが働くため、運用手順としても残しやすいですね。
offへ戻すと権限エラーが設計の手掛かりになる
冒頭の問いへの答えは、onを見つけてもすぐに全体設定を切り替えず、アプリケーションと同じ接続条件で実効値を確定し、offで失敗する操作を特定してから所有者またはACLを直す、です。
lo_compat_privileges = offは単なる推奨値ではありません。PostgreSQL 9.0以降の「誰が読めるか、書けるか、削除できるか」という設計を再び有効にし、権限エラーを調査可能な情報へ戻します。
ラージオブジェクトを使う環境では、設定値だけで監査を終えず、pg_largeobject_metadata、接続ロール、保守ジョブまで一つの権限モデルとして見直すことが実務上の着地点です。
出典
- Title: Christophe Pettus: All Your GUCs in a Row: lo_compat_privileges
- URL: https://postgr.es/p/9sZ
Share
Related Articles
カテゴリやタグが近い記事を続けて読めるように並べています。




