create-readonly-db-role について
エージェント向けに保護された SELECT 専用のデータベースロールを準備するスキルです。本番環境の変更は人が適用し、機密テーブルの除外と読み取り専用設定の検証を重視します。
主な機能
- 01SELECT 専用ロールと権限
- 02機密テーブルの除外リスト
- 03読み取り専用とタイムアウトの保護
- 04人による SQL 変更の適用
- 05接続と権限の確認
- 06ロールのメンテナンス案内
活用シーン
- 01エージェントに限定的なデータベース読み取り権限を付与
- 02エージェントのクエリから機密情報や個人情報を除外
- 03データベースの書き込み保護を検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davidondrej/ skills --skill create-readonly-db-roleインストール後、Claude Code で/create-readonly-db-roleを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yaml
詳細
エージェント用の読み取り専用 DB ロールを作成する
SELECT のみを許可するロールと、保護された接続を用意します。SQL、ロール名、権限付与、拒否リスト、RLS の設定、タイムアウト、接続手順は、実際のシステムに合わせて調整するための例であり、本番環境でそのまま使える設定ではありません。
アクセスモデル
- SELECT のみを許可します。 書き込み権限は付与せず、拒否リストを使ってシークレットや PII を除外します。
- 現在および将来のテーブルを対象にします。
public内のすべてのテーブルに SELECT を付与し、デフォルト権限を通じて将来のテーブルにも適用したうえで、拒否リストにあるテーブルの権限を取り消します。authスキーマには決して権限を付与しないでください。新しく追加された機密テーブルについては、手動で権限を取り消す必要があります。 - 緩やかな保護策を設定します。
default_transaction_read_only = onと、ワークロードに適した短いstatement_timeoutを設定します。
RLS: 適用されるポリシーがないロールでは、テーブルから行が返されないことがあります。セキュリティモデルに合う場合に限り、bypassrls を検討してください。これは行のフィルタリングをスキップしますが、権限付与と拒否リストは引き続き適用されます。
ワークフロー
- ロールを確認します:
select rolname from pg_roles where rolname = 'agent_reader';。任意の名前を選んでください。すでに存在する場合は、再作成せずに更新します。 - 拒否リストを人間と合意します。 エージェントに決して見せてはならないシークレットや PII を含むテーブルを特定します。例として、認証情報、Webhook ペイロード、ID テーブルなどがあります。
- SQL をリポジトリに保存します。 たとえば、
docs/database/create-agent-reader-role.sqlです。変更内容、理由、適用方法、検証方法、元に戻す方法をコメントに記載します。チャットに SQL を記載するだけでは不十分です。 - 人間が適用します。エージェントは本番環境の DDL を実行しません。 Supabase では、ファイルの内容を SQL エディターに貼り付け、その後、パスワードが含まれているため、クエリ履歴からクエリを削除します。人間がパスワードマネージャーにパスワードを保管します。
- 保護されたシークレットマネージャーまたはローカルの環境設定を通じて接続を設定し、決してコミットしないでください。 Supabase のセッションプーラーでは通常、ポート 5432 で
<role>.<project-ref>を使用します。psqlがない場合はインストールします(macOS では Homebrew のlibpqを使用します)。 - 以下の検証項目をすべて実行します。
- プロジェクト固有の利用スキルを作成します。 主なテーブル、クエリパターン、読み取り専用アクセス、PII をコミットやドキュメントに決して貼り付けないことを含めます。
SQL テンプレート
-- Example only. Rename the role, timeout, and denylist for your system.
-- 1. role + soft guardrails
create role agent_reader with login password 'REPLACE_ME';
alter role agent_reader set default_transaction_read_only = on;
alter role agent_reader set statement_timeout = '10s'; -- example timeout; change as needed
-- 2. SELECT-only grants, denylist model
grant usage on schema public to agent_reader;
grant select on all tables in schema public to agent_reader;
alter default privileges for role postgres in schema public
grant select on tables to agent_reader; -- future tables auto-readable
-- 3. denylist: keep secrets and PII invisible (replace with your own tables)
revoke select on table public.secrets from agent_reader;
revoke select on table public.private_events from agent_reader;
-- 4. only if RLS is enabled, no policy covers this role, and bypass fits your model
alter role agent_reader bypassrls;
元に戻すには:drop owned by agent_reader; drop role agent_reader;
検証
完了を宣言する前に、すべてのチェックに合格する必要があります:
# Load the connection URL from your secret manager or local environment configuration.
psql "<readonly-connection-url>" -X -c "select current_user;" # -> agent_reader
psql "<readonly-connection-url>" -X -c "show statement_timeout;" # -> matches your chosen timeout
psql "<readonly-connection-url>" -X -c "select count(*) from public.<big_table>;" # -> real number, NOT 0
psql "<readonly-connection-url>" -X -c "delete from public.<any_table> where false;"
# -> ERROR: read-only transaction (soft guardrail)
psql "<readonly-connection-url>" -X -c "begin; set transaction read write; delete from public.<any_table> where false; rollback;"
# -> ERROR: permission denied (the hard wall)
psql "<readonly-connection-url>" -X -c "select * from public.<denylisted> limit 1;" # -> ERROR: permission denied
psql "<readonly-connection-url>" -X -c "select * from auth.<identity_table> limit 1;" # -> ERROR: permission denied
両方の保護を検証します。読み取り専用の保護策が有効な状態では書き込みに失敗し、無効な状態でも permission denied で失敗することを確認します。いずれかのチェックに失敗した場合は、人間を通じて設定を修正し、すべてのチェックを再実行します。
トラブルシューティングとメンテナンス
- どのテーブルからも行が返されない: RLS ポリシーを確認します。適切な場合に限り、
bypassrlsを使用します。 - 書き込みの検証が成功する: 作業を中止します。人間にロールの権限を取り消して設定を修正してもらい、すべてのチェックを再実行します。
- Supabase の認証に失敗する: プーラーのユーザー名を確認します。通常は
<role>.<project-ref>です。 - 正当なクエリがタイムアウトする: タイムアウトを延長する前に、フィルターや上限を追加します。
- 機密テーブルが新たに追加された: 拒否リストに
revoke selectを追加します。 - パスワードをローテーションする: 人間に
alter role agent_reader with password '...'を実行してもらい、保存済みの接続シークレットを更新します。 - このロールを通じてエージェントに書き込みを決して許可しないでください。本番環境への書き込みは、引き続き人間のみが行います。
コメント
Markdown 対応