queryshield について
QueryShieldは、エージェントが顧客データベースや許可されたシークレットへ制御下でアクセスするためのSQLプロキシと認証情報保管庫です。質問をSQLに変換し、AST検査とエージェントごとの行レベル制御を適用して、メタデータのみを監査記録に残します。
主な機能
- 01自然言語の質問をSQLに変換
- 02検証済みでLIMIT付きのSELECTのみ許可
- 03スキーマ、テーブル、行単位のアクセス制御
- 04許可された認証情報を暗号化保管
- 05結果行を保存せずクエリー試行を記録
活用シーン
- 01エージェントによる自然言語でのデータベース検索
- 02許可されたテーブルと行へのアクセス制限
- 03明示的に許可したAPIシークレットの提供
- 04エージェントの最近のデータベース操作の確認
MCP 対応
queryshield-mcpパッケージは、データベース検索、認証情報、監査ログのツールをMCPクライアントに公開します。リポジトリにはPythonモジュールを使う旧式のMCPサーバーも記載されています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
3掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| max_rows | integer | いいえ | 返される行数の上限(デフォルト 100、上限 5000)。 |
| question | string | はい | 自然言語の質問。 |
| database_alias | string | はい | このテナントに登録されたデータベースのエイリアス。 |
詳細
QueryShield
エージェント向けセキュリティスイートです。QueryShield は中核製品で、安全な SQL プロキシと名前付き認証情報ボルトを提供します。API キーは qs_ の 1 つ、Stripe の顧客情報も 1 つで、このドキュメントサイトも含まれます。
エージェントは、自然な英語(または構造化 SQL)で単一のエンドポイントを呼び出します。QueryShield は次の処理を行います。
- Claude とプロンプトキャッシュを使用して、自然言語を SQL に変換します。
- すべてのクエリを AST レベルで検証します。許可されるのは
SELECTのみで、複数のステートメントの連結や禁止関数は認められず、LIMIT が必須です。 - エージェントごとに行レベルのセキュリティを適用します。スキーマ/テーブルの許可リストと
WHERE句の挿入を行います。 - 顧客の DB に対して実行し、行を返します。
- すべての試行を追加専用の監査テーブルに記録します。記録するのはメタデータのみで、行の内容は記録しません。
エージェントに接続文字列が見えることはありません。
認証情報ボルトには、エージェントによる使用が許可された API トークンなど、その他のシークレットが保存されます。これは AgentVault 製品をこのサービスに統合したものです。権限パターンによって、エージェントが読み取れる名前が決まります。データベース接続文字列は別の暗号化ストアに保管され、ボルト経由では読み取れません。
無料プラン/導線: InjectShield は、信頼できないテキストのプロンプトインジェクションをスキャンします。独自のリポジトリ(bch1212/injectshield)と独自の API(api.injectshield.dev)で提供されています。まずはこちらを利用し、エージェントにデータベースまたはボルトが必要になったら、QueryShield ワークスペースを 1 つ作成してください。ドキュメント:injectshield.dev/docs。このサービスのスイートページ:/suite。
クイックスタート
pip install -r requirements.txt
cp .env.example .env
# Set ANTHROPIC_API_KEY, DATABASE_URL, and VAULT_KEY in .env (see below).
# Do not commit .env. QueryShield reads secrets from the environment only.
python -m queryshield.start
VAULT_KEY 用の Fernet キーを一度生成し、絶対になくさないでください。認証情報の暗号化とセッション署名には、どちらも VAULT_KEY(または Cookie 用の SESSION_KEY)が必要です。設定されていない場合、組み込みキーを使用せず、これらの操作は失敗します。
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
エンドツーエンドのフロー(curl)
# 1) Boot a tenant. Returns the admin API key — copy it.
curl -X POST localhost:8000/v1/tenants?name=Acme
# 2) Register the customer DB. Connection string is encrypted at rest.
curl -X POST localhost:8000/v1/databases \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"alias": "prod",
"db_type": "postgresql",
"connection_string": "postgresql://READER:[email protected]:5432/app",
"allowed_tables": ["users", "orders"]
}'
# 3) Provision a scoped agent (different from admin) for your AI app.
curl -X POST localhost:8000/v1/agents \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{ "name": "reporting", "tenant_id": "<tenant>" }'
# 4) Set the agent's RLS policy.
curl -X POST localhost:8000/v1/policies \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"agent_id": "<agent>",
"database_alias": "prod",
"allowed_tables": ["users", "orders"],
"row_filters": { "users": "tenant_id = 42" }
}'
# 4b) Store a named credential and let one agent read it.
# The value is write-only on this call. Empty permissions grant nothing.
curl -X POST localhost:8000/v1/credentials \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"name": "openai_key",
"provider": "openai",
"value": "YOUR_SECRET"
}'
curl -X POST localhost:8000/v1/agents \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"name": "writer",
"tenant_id": "<tenant>",
"credential_permissions": ["openai_*"],
"budget_daily": 5
}'
# The agent uses the same qs_ key it uses for /v1/query.
curl -X POST localhost:8000/v1/vault/get/openai_key \
-H 'X-API-Key: qs_...'
# 5) The agent queries.
curl -X POST localhost:8000/v1/query \
-H 'X-API-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"database_alias": "prod",
"query": "how many active users do we have?",
"mode": "nl",
"max_rows": 10
}'
MCP 連携
公式 MCP Registry に io.github.bch1212/queryshield として登録されています。
クライアントをインストールします。
pip install queryshield-mcp
次に、これを Claude Desktop/Cursor/エージェントの設定に追加します。
{
"queryshield": {
"command": "queryshield-mcp",
"env": { "QUERYSHIELD_API_KEY": "qs_..." }
}
}
スタンドアロンの PyPI パッケージのソースは packages/queryshield-mcp/ にあります。
Glama などの MCP ディレクトリ評価者向けに、リポジトリのルートには、公開済みの queryshield-mcp stdio サーバーを起動してツールをイントロスペクションする簡易版 Dockerfile も含まれています。コンテナでは MCP の初期化やツールの検出に QUERYSHIELD_API_KEY は必要ありません。このキーが必要になるのは、検出されたツールを QueryShield API テナントに対して実際に呼び出す場合のみです。
MCP 連携(レガシー)
MCP 対応のクライアント(Claude Desktop、Cursor、カスタムエージェント)にこれを追加します。
{
"queryshield": {
"command": "python",
"args": ["-m", "queryshield.mcp_server"],
"env": {
"QUERYSHIELD_API_KEY": "qs_...",
"QUERYSHIELD_BASE_URL": "https://api.queryshield.io"
}
}
}
公開されるツール:
query_database(database_alias, question, max_rows)— 自然言語によるクエリquery_database_sql(database_alias, sql, max_rows)— あらかじめ作成された SELECT クエリlist_credentials()— このエージェントが読み取りを許可されている名前get_credential(name, cost)— 許可されたシークレットを 1 つ取得(同じ API キーを使用)get_audit_log(limit)— 呼び出し元のエージェントによる最近の試行
PyPI パッケージ queryshield-mcp では、次のリリースでボルトのツールが利用可能になります。それまでは、このリポジトリから python -m queryshield.mcp_server を実行すれば、すでにそれらのツールを利用できます。
セキュリティモデル
| 脅威 | 防御 |
|---|---|
エージェントが DROP TABLE を作成する | sqlglot AST が SELECT 以外を拒否します |
エージェントが ; と2つ目のステートメントを紛れ込ませる | パーサーが len(statements) > 1 を拒否します |
エージェントが pg_sleep、xp_cmdshell などを使用する | AST ノードレベルで関数の拒否リストを適用します |
| エージェントがスコープ外のテーブルを読み取る | RLS スキーマ + テーブル許可リスト |
| エージェントが他のテナントの行を読み取る | row_filters を AST の .where() で挿入します |
| スタックトレースから接続文字列が漏えいする | Fernet で暗号化し、いずれの API からも返しません |
| エージェントが許可されていないシークレットを読み取る | fnmatch による権限チェック。空のリストはデフォルトで拒否します |
| Vault の監査ログにシークレットが含まれる | 認証情報アクセスログにはメタデータのみを保存します |
| 監査ログがデータ流出の経路になる | メタデータのみを保存し、行データは保存しません |
VAULT_KEY のローテーション | 新しいキーで行を再暗号化します(スクリプトで実行) |
safety.py は最も重要なモジュールです。ここに追加するすべてのチェックには、
tests/test_safety.py のテストも含めてください。
料金
| プラン | 月額 | データベース | 認証情報 | 月間クエリ数 | 備考 |
|---|---|---|---|---|---|
| InjectShield | 無料 | — | — | — | プロンプトインジェクションの窓口、別サイト |
| Starter | $500 | 3 | 25 | 1,000,000 | |
| Pro | $1,500 | 10 | 100 | 10,000,000 | 監査ログのエクスポート |
| Enterprise | $3,500 | 無制限 | 無制限 | 無制限 | SSO、SIEM Webhook |
QueryShield のプランは、1つの Stripe 顧客に紐づきます。InjectShield の課金を統合するまでは、サインアップは injectshield.dev で行います。目標は 15社(Pro 10社 + Enterprise 5社)で MRR $32.5K です。
デプロイ
このリポジトリは Railway 対応です。python -m queryshield.start がエントリーポイントです
(Railway はシェルを介さずに起動コマンドを実行するため、os.getenv を使って
PORT を読み取ります)。Railway のマーケットプレイスから Postgres と(任意で)Redis を
プロビジョニングし、残りは環境変数で設定します。
railway up
/health は稼働状態のチェックです。コントロールプレーンの
DB に接続できない場合、/ready は 503 を返します。
テスト
pip install pytest
python -m pytest tests/
102件のテストで、既存の安全性、RLS、プロキシ、HTTP の各テストスイートに加え、認証情報 Vault(暗号化、qs_ キーのハッシュ化、権限チェック、予算、テナント分離、既存データベース向けのカラム移行)と、デフォルトで拒否する VAULT_KEY / SESSION_KEY のチェックを網羅しています。既存のテストケースは次のとおりです。
- AST の安全性(24ケース — 直接的な DDL、コメント、エンコードされたキーワード、複数の ステートメント、禁止された関数、LIMIT の欠落)
- RLS エンジン(6ケース — 許可リストの適用、WHERE の挿入、既存の条件との結合)
- SQLite の「顧客 DB」に対するプロキシのエンドツーエンドテスト(5ケース — 正常系、 DML のブロック、RLS による行フィルタリング、テーブル許可リスト、キャッシュヒット)
- FastAPI TestClient を使った HTTP 統合テスト(7ケース — プロビジョニングからクエリまでの 一連のフロー、RLS を適用したスコープ付きエージェント、認証エラー)
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。