Configuration Guide Community
Querycop の全環境変数リファレンスです。全ての設定は環境変数で行います。一部の設定はCLIフラグでも指定可能です。
1. プロキシ設定
Section titled “1. プロキシ設定”基本的なプロキシ動作を制御する設定です。
| 環境変数 | デフォルト | CLIフラグ | 説明 |
|---|---|---|---|
GATEKEEPER_LISTEN_PORT | 5432 | --listen-port | プロキシのリッスンポート。クライアント(psql, DBeaver等)はこのポートに接続します |
GATEKEEPER_BACKEND_HOST | localhost | --backend-host | バックエンドデータベースのホスト名またはIPアドレス |
GATEKEEPER_BACKEND_PORT | 5433 | --backend-port | バックエンドデータベースのポート番号 |
GATEKEEPER_API_PORT | 8080 | --api-port | 管理API/ダッシュボードのHTTPポート |
GATEKEEPER_APPROVAL_TIMEOUT | 30 | --approval-timeout | 承認待ちのタイムアウト秒数。超過するとクエリは自動的に却下されます |
GATEKEEPER_PENDING_MAX | 10000 | - | 同時保持する pending 承認待ちクエリの上限。超過時は新規リクエストを即座に拒否(DoS 耐性) |
GATEKEEPER_DB_TYPE | postgresql | - | データベースのWire Protocol種別。postgresql または mysql |
# ポートをカスタマイズexport GATEKEEPER_LISTEN_PORT=15432export GATEKEEPER_BACKEND_HOST=db.example.comexport GATEKEEPER_BACKEND_PORT=5432export GATEKEEPER_API_PORT=9090export GATEKEEPER_APPROVAL_TIMEOUT=60# MySQL接続の場合export GATEKEEPER_DB_TYPE=mysqlexport GATEKEEPER_BACKEND_PORT=33061.5 Backend TLS
Section titled “1.5 Backend TLS”Managed cloud DB (AWS RDS / Aurora / Cloud SQL / AlloyDB / Neon / Supabase /
PlanetScale 等) は全て TLS 強制が前提なので、Querycop はバックエンド
(GATEKEEPER_BACKEND_HOST) への接続でも TLS をネゴシエートできます。
PostgreSQL・MySQL とも対応済み。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_BACKEND_TLS_MODE | DBType 別。PostgreSQL: prefer / MySQL: disable | libpq の sslmode と同じ値: disable / prefer / require / verify-ca / verify-full |
GATEKEEPER_BACKEND_TLS_CA_FILE | (なし) | PEM 形式の CA bundle ファイル。verify-ca / verify-full で 必須 — 暗黙的な system root pool への fallback は意図的に無効化 (環境差を減らすため) |
GATEKEEPER_BACKEND_TLS_SERVER_NAME | (なし、空なら BACKEND_HOST から派生) | SNI / hostname verification のためのサーバー名 override。Neon の compute endpoint や Supabase の pooler のように SNI でルーティングする managed DB では必須 |
default が DBType 別になっている理由
Section titled “default が DBType 別になっている理由”- PostgreSQL の
prefer: libpq の既定と一致。SSLRequest→ サーバがSかNを返すクリーンな negotiation contract があり、Nでの plaintext fallback が安全に書ける。既存 plaintext-only PostgreSQL deployment はそのまま動く。 - MySQL の
disable: MySQL のCLIENT_SSLcapability flag は handshake の前半 (auth 前) に立てる必要があり、PG の “S or N” のような明示的拒否表現がない。preferを default にすると negotiation の見え方が複雑で「TLS-attempt 失敗時の plaintext fallback」が runtime ログから読み取りづらいので、初期値は最も安全なdisable。managed MySQL を使う場合は cookbook でrequire/verify-fullを明示推奨。
sslmode 別の動作
Section titled “sslmode 別の動作”PostgreSQL backend
Section titled “PostgreSQL backend”| mode | 振る舞い |
|---|---|
disable | TLS 一切ネゴシエートしない (素の TCP) |
prefer (PG default) | SSLRequest を送り、backend が S を返せば TLS upgrade、N を返せば plaintext で続行 (INFO ログ) |
require | TLS 必須。証明書検証はしない。N を受けたら fail |
verify-ca | TLS 必須 + 証明書チェーンを CA bundle で検証 (hostname 検証はスキップ)。CA file 必須 |
verify-full | TLS 必須 + チェーン検証 + hostname 検証。CA file + ServerName 必須。IP literal の host は検証不能 (明示エラーで起動拒否) |
MySQL backend
Section titled “MySQL backend”| mode | 振る舞い |
|---|---|
disable (MySQL default) | TLS 一切ネゴシエートしない |
prefer | Initial Handshake で server が CLIENT_SSL capability を advertise していれば TLS upgrade (SSL Request Packet を seq=1 で送る → tls.Client handshake → 以降の client Response は seq=2 に rewrite)。CLIENT_SSL が無ければ plaintext で続行 (INFO ログ) |
require | TLS 必須。server が CLIENT_SSL を advertise していなければ first-connection error (server capability は起動時には見られないので、最初の connection 時に検出) |
verify-ca | TLS 必須 + チェーン検証。CA file 必須。CLIENT_SSL 無しは first-connection error |
verify-full | TLS 必須 + チェーン検証 + hostname 検証。CA file + ServerName 必須。IP literal は起動時 fail-fast |
検証エラーの起動時 fail-fast (PG + MySQL 共通)
Section titled “検証エラーの起動時 fail-fast (PG + MySQL 共通)”設定ミスは起動時に検出して fail-fast します:
verify-ca/verify-fullでCA_FILE未設定 → 起動拒否verify-fullでSERVER_NAME未設定かつBACKEND_HOSTが IP literal → 起動拒否CA_FILEが読めない / PEM ブロックを含まない → 起動拒否- 未知の
MODE値 → 起動拒否
MySQL 固有の first-connection error: require / verify-* で MySQL backend が CLIENT_SSL を advertise していない場合は、起動時には検出できず最初の connection で失敗します (server capability は initial handshake 時にしか分からない)。これは documented behavior。
Client→proxy TLS (MySQL) は未実装: Querycop は MySQL では proxy↔backend (= Querycop ↔ DB) の TLS を terminate しますが、client↔proxy (= app ↔ Querycop) の MySQL TLS handshake は未実装です。そのため Querycop は backend から受け取った Initial Handshake の CLIENT_SSL capability bit を client に転送する前にクリアします (これをしないと、ssl-mode=PREFERRED の MySQL client が proxy 相手に TLS upgrade を試みてしまい handshake が破綻する)。PostgreSQL では client TLS termination が利用可能 (GATEKEEPER_PROXY_TLS_CERT/KEY)。MySQL でも同じことをしたい場合は proxy の前段に TLS terminating LB (HAProxy、stunnel など) を置いてください。client→proxy MySQL TLS は将来の epic で扱います。
1.6 Backend IAM token injection
Section titled “1.6 Backend IAM token injection”Managed cloud DB の IAM 認証 (AWS RDS IAM auth / Cloud SQL IAM auth / AlloyDB IAM 等) では、固定パスワードの代わりに 短命 (15分等) の token をパスワード フィールドに入れて認証します。Querycop はこれを proxy が接続ごとに mint する 方式でサポートします。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_BACKEND_TOKEN_CMD | (なし、空) | Operator が指定する shell command。Querycop は接続ごとにこれを実行し、stdout (trim 後) を IAM token としてバックエンドの認証フィールドに埋め込む |
接続が来ると Querycop は以下を行います:
QUERYCOP_BACKEND_USER(DB user 名) /QUERYCOP_BACKEND_HOST(backend host:port) を 環境変数として 設定して shell command を実行 (10s timeout)- stdout を
strings.TrimSpace、empty なら error → connection abort - PostgreSQL backend:
- StartupMessage を forward
- server の
Authentication*request を読む AuthenticationCleartextPassword(R=3): token をPasswordMessageとして送信AuthenticationMD5Password(R=5): server-supplied salt と user から MD5 hash を計算 (md5(md5(token + user) + salt))、md5...prefix 付きでPasswordMessage送信AuthenticationSASL/SCRAM(R=10/11/12): 現状は非対応、connection abort。SCRAM 対応は将来予定
- MySQL backend:
- 既存の Phase 1/2 handshake で server greeting を読み、TLS upgrade
- client の Handshake Response Packet を読む
- client の auth plugin が
mysql_clear_passwordの場合のみ、auth-data field を token で書き換えて backend に送信 - それ以外の plugin (
mysql_native_password等) なら connection abort (fail-closed)
- token mint command 失敗 (non-zero exit / empty stdout / timeout) → connection abort、client password fallback はしない。fallback すると IAM auth が落ちているのに通常 password で通る可能性があり operator に気づかれにくいため
安全ガード: TLS mode が require 以上必須
Section titled “安全ガード: TLS mode が require 以上必須”GATEKEEPER_BACKEND_TOKEN_CMD が設定されている場合、Querycop は起動時に
GATEKEEPER_BACKEND_TLS_MODE が require / verify-ca / verify-full
のいずれかであることを確認します。それ以外 (disable / prefer / 未設定)
は 起動拒否。
prefer は backend が 'N' (no SSL) を返した時 plaintext fallback に降りる
可能性があり、その場合 IAM token が cleartext で送られてしまいます。
これを防ぐため、cookbook では require 以上を必須要件とします。
操作者向け運用ノート
Section titled “操作者向け運用ノート”- MySQL client の plugin 指定: AWS の MySQL IAM auth は cleartext plugin
経由なので、client 側で
--enable-cleartext-plugin(mysql client) やuseSSL=true&useServerPrepStmts=false+ cleartext plugin (JDBC connector) 等を設定する必要があります。Querycop は cleartext plugin 以外を fail-closed で拒否するので、client config を上手く揃えないと connection が立ちません - shell interpolation 防止: command 文字列内で
$QUERYCOP_BACKEND_USER/$QUERYCOP_BACKEND_HOSTを referenced できますが、%s等の Go-side interpolation は しません。これは shell metacharacter (;,&&, backtick) が user 名に紛れ込んだ場合の injection を防ぐためです - token は決してログに出ません。command の stderr は失敗時のみ 256 bytes に truncate してログ出力します
- connection per token: command は 接続ごとに 1 回 実行されます。 接続が長寿命でも token は再 mint されません (短命 token を使う設計上、 接続中に expire する可能性がある — proxy topology epic で扱う)
Examples
Section titled “Examples”AWS RDS IAM auth (PostgreSQL)
Section titled “AWS RDS IAM auth (PostgreSQL)”export GATEKEEPER_BACKEND_HOST=mydb.cluster-xxxxx.us-east-1.rds.amazonaws.comexport GATEKEEPER_BACKEND_PORT=5432export GATEKEEPER_BACKEND_TLS_MODE=verify-fullexport GATEKEEPER_BACKEND_TLS_CA_FILE=/etc/ssl/certs/rds-ca-rsa2048-g1.pemexport GATEKEEPER_BACKEND_TOKEN_CMD='aws rds generate-db-auth-token \ --hostname "$QUERYCOP_BACKEND_HOST" --port 5432 \ --region us-east-1 --username "$QUERYCOP_BACKEND_USER"'Cloud SQL IAM auth (PostgreSQL)
Section titled “Cloud SQL IAM auth (PostgreSQL)”export GATEKEEPER_BACKEND_HOST=10.20.30.40 # private IP via Cloud SQL Auth Proxy not needed if direct IPexport GATEKEEPER_BACKEND_PORT=5432export GATEKEEPER_BACKEND_TLS_MODE=verify-fullexport GATEKEEPER_BACKEND_TLS_CA_FILE=/etc/cloudsql/server-ca.pemexport GATEKEEPER_BACKEND_TOKEN_CMD='gcloud sql generate-login-token'AWS RDS IAM auth (MySQL)
Section titled “AWS RDS IAM auth (MySQL)”export GATEKEEPER_DB_TYPE=mysql # Pro license requiredexport GATEKEEPER_BACKEND_HOST=mymysql.cluster-xxxxx.us-east-1.rds.amazonaws.comexport GATEKEEPER_BACKEND_PORT=3306export GATEKEEPER_BACKEND_TLS_MODE=verify-fullexport GATEKEEPER_BACKEND_TLS_CA_FILE=/etc/ssl/certs/rds-ca-rsa2048-g1.pemexport GATEKEEPER_BACKEND_TOKEN_CMD='aws rds generate-db-auth-token \ --hostname "$QUERYCOP_BACKEND_HOST" --port 3306 \ --region us-east-1 --username "$QUERYCOP_BACKEND_USER"'# Client must use mysql_clear_password plugin:# mysql --enable-cleartext-plugin -u iam_user -h querycop ...- SASL/SCRAM 非対応 (PostgreSQL): 将来対応予定
- MySQL は
mysql_clear_passwordplugin 限定: 他の plugin は fail-closed - connection 中の token rotation 未対応: 接続ごと 1 回 mint。長時間接続で token が expire したら connection drop → 再接続が必要
managed DB 別の推奨設定 (詳細は cloud-db cookbook を参照)
Section titled “managed DB 別の推奨設定 (詳細は cloud-db cookbook を参照)”| Provider | DBType | MODE | CA file | SNI |
|---|---|---|---|---|
| AWS RDS / Aurora PostgreSQL | postgresql | verify-full | RDS が公開する rds-ca-rsa2048-g1 等 | デフォルト OK |
| Cloud SQL PostgreSQL (direct) | postgresql | verify-full | Cloud SQL の server CA を export | デフォルト OK |
| Neon | postgresql | verify-full | Let’s Encrypt | <endpoint-id>.<region>.aws.neon.tech を明示 (compute routing) |
| Supabase pooler | postgresql | verify-full | Let’s Encrypt | デフォルト OK |
| AlloyDB (direct) | postgresql | verify-full | AlloyDB CA bundle | デフォルト OK |
| AWS RDS / Aurora MySQL | mysql | verify-full | rds-ca-rsa2048-g1 等 (PG と同じ) | デフォルト OK |
| PlanetScale | mysql | require または verify-full | system root から Let’s Encrypt を export | デフォルト OK |
| 自前運用 PostgreSQL/MySQL (TLS なし) | — | disable | — | — |
既存環境からの移行
Section titled “既存環境からの移行”- PostgreSQL: default の
preferは既存 plaintext PostgreSQL も壊しません。SSLRequestにNが返り INFO ログ 1 行 (backend declined TLS; continuing in plaintext) を残して plaintext で続行。ログを完全に静かにしたい場合はGATEKEEPER_BACKEND_TLS_MODE=disableを明示。 - MySQL: default の
disableは従来どおりの挙動。managed MySQL を使う場合は 明示的にrequire以上を設定してください。プレーン MySQL 環境からの upgrade では何も変わりません。
1.7 Backend pooler awareness flag
Section titled “1.7 Backend pooler awareness flag”Querycop の backend が PgBouncer / Supavisor / RDS Proxy / Vitess (PlanetScale) 等の connection pooler を経由している場合、その topology を Querycop に 伝えるためのフラグです。観測性専用 — Querycop はこの値を見て client SQL を 検査・拒否したりはしません。Pool 層の制約 (transaction-mode で session GUC が 切れる等) は pool 層自身が client に error を返すのが正しい責務分担で、 Querycop が二重に enforce すると複数 port を併用する topology を壊します。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_BACKEND_POOLER | (空、silent default) | Backend pooler topology hint。none / pgbouncer-txn / pgbouncer-session / vitess のいずれか。不正値は起動時 fail-fast |
受け入れる値
Section titled “受け入れる値”| 値 | 該当する topology | 起動時の挙動 |
|---|---|---|
"" / none | 直接接続 (pooler なし) | silent — 起動ログを汚さない |
pgbouncer-txn | PgBouncer / Supavisor / RDS Proxy が transaction mode | INFO 1 行 — session GUC / LISTEN/NOTIFY / advisory lock / temp table が COMMIT を跨がない / SQL-level PREPARE/EXECUTE が永続しない、を一覧 |
pgbouncer-session | PgBouncer / Supavisor が session mode | INFO 1 行 — connection density 経路だが session 意味論は維持 |
vitess | Vitess proxy (PlanetScale 等) | INFO 1 行 — docs/cloud-db/planetscale.md の Vitess gotcha 節をクロスリンク |
- 値が
""またはnoneの場合、Querycop は何も log せず、proxy の挙動は フラグ未導入時と完全に同一です。Library embedder がConfig.BackendPoolerを 未設定でproxy.New(cfg)を呼ぶケースも同様。 - 不正値 (大文字小文字混在、typo、provider 名の推測等) は起動時に
os.Exit(1)で fail-fast。BACKEND_TLS_MODE/BACKEND_TOKEN_CMDの validation と同じパターンで、typo silent fallback を防ぎます。 - 値は metric label には載りません (現状は deferred、ダッシュボードの 需要が顕在化したら follow-up で追加予定)。
Cookbook で使う場面
Section titled “Cookbook で使う場面”docs/cloud-db/index.md の “Pooler awareness flag” 表を参照してください。
要約:
- Neon の
-poolerendpoint →pgbouncer-txn - Supabase Supavisor (port 6543) →
pgbouncer-txn - Supabase Supavisor (port 5432) →
pgbouncer-session - PlanetScale (常時 Vitess 経由) →
vitess - それ以外の cookbook ページ (RDS direct, Cloud SQL, AlloyDB, Azure PG,
CockroachDB Cloud, Timescale Cloud 等) → 未設定 (=
none)
2. AI設定
Section titled “2. AI設定”AIリスク評価エンジンの設定です。SQLクエリの危険度を0-100でスコアリングします。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
AI_PROVIDER | openai | AIプロバイダー。openai / anthropic / gemini / ollama のいずれか |
AI_API_KEY | (なし) | AIプロバイダーのAPIキー。ollama 以外は必須 |
AI_ENDPOINT | (プロバイダー既定) | AIのAPIエンドポイントURL。カスタムエンドポイントやプロキシ経由で接続する場合に設定 |
AI_MODEL | (プロバイダー既定) | 使用するモデル名 (FeatureAdvancedAIProvider, Pro+)。Community では設定しても無視され provider 既定モデルが使われる (起動時に INFO ログ)。AI_SYSTEM_PROMPT と同じ二層 gate (起動時 build + AnalyzeSQL ごとに live license 再確認 → heartbeat downgrade 時は即座に既定モデルへ戻る)。multi-provider / fallback は未実装 (roadmap) |
AI_SYSTEM_PROMPT | (なし、組み込み既定 prompt) | リスクスコアリングの system prompt を上書きする (FeatureCustomAIPrompt, Pro+)。Community では設定しても無視され組み込み既定 prompt が使われる (起動時に INFO ログ)。二層 gate: 起動時に license を見て build、かつ AnalyzeSQL ごとに live license を再確認するため heartbeat downgrade 時は即座に既定 prompt に戻る。注意: ここに入れた prompt は operator が信頼する設定として LLM へそのまま渡される。SQL payload 側の PII redaction (GATEKEEPER_AI_PII_REDACTION) は引き続き適用される |
GATEKEEPER_AI_PII_REDACTION | true | AI 送信前に SQL 中の PII (email/電話番号/クレジットカード/SSN/マイナンバー/IPアドレス) を [EMAIL] / [PHONE] / [CC] / [SSN] / [MYNUMBER] / [IP] などの placeholder に置換する。false / 0 / off / no で opt-out |
注意:
AI_API_KEYが未設定かつプロバイダーがollama以外の場合、AIリスク評価は無効になります。その場合、RBACポリシーのみで判定が行われます。
AI PII Redaction (S-03)
Section titled “AI PII Redaction (S-03)”Querycop はデフォルトで、外部 AI プロバイダ (OpenAI / Anthropic / Gemini) に SQL を送信する前に、SQL 中の PII を placeholder に置換します。
| PII 種別 | placeholder | 検知パターン例 |
|---|---|---|
| メールアドレス | [EMAIL] | [email protected] |
| クレジットカード番号 | [CC] | 4111-1111-1111-1111 / 4111 1111 1111 1111 |
| 電話番号 | [PHONE] | +81-90-1234-5678 / 090-1234-5678 / 03-1234-5678 |
| SSN (米国) | [SSN] | 123-45-6789 |
| マイナンバー | [MYNUMBER] | 1234 5678 9012 |
| 郵便番号 (〒) | [POSTAL] | 〒123-4567 |
| IPv4 アドレス | [IP] | 192.168.1.1 |
- スコアリング品質を保つため、PII は削除ではなく placeholder 化します。AI は「email 列の検索」「credit card のバルク更新」といった文脈を失いません。
- 既定値は
true。ローカル推論 (AI_PROVIDER=ollama) でも redaction は適用されます。Opt-out するにはGATEKEEPER_AI_PII_REDACTION=falseを設定。 - 保守的 (false positive 許容) に実装しているため、偶発的な数字列が placeholder に置換されることがあります。スコア判定への影響は軽微です。
プロバイダー別設定例
Section titled “プロバイダー別設定例”OpenAI
Section titled “OpenAI”export AI_PROVIDER=openaiexport AI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxexport AI_MODEL=gpt-4o # オプションAnthropic Claude
Section titled “Anthropic Claude”export AI_PROVIDER=anthropicexport AI_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxxxexport AI_MODEL=claude-sonnet-4-20250514 # オプションGoogle Gemini
Section titled “Google Gemini”export AI_PROVIDER=geminiexport AI_API_KEY=AIzaXXXXXXXXXXXXXXXXXXXXexport AI_MODEL=gemini-pro # オプションOllama(ローカルLLM)
Section titled “Ollama(ローカルLLM)”export AI_PROVIDER=ollama# AI_API_KEYは不要export AI_ENDPOINT=http://localhost:11434 # オプション(Ollamaデフォルト)export AI_MODEL=llama3 # オプション3. RBAC設定
Section titled “3. RBAC設定”ロールベースアクセス制御の設定です。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_ROLES | (なし) | ユーザーへのロール割り当て。形式: role:user1,user2;role2:user3 |
GATEKEEPER_POLICY_FILE | (なし) | JSONポリシーファイルのパス。カスタムルールやロール設定を定義 |
優先順位:
GATEKEEPER_POLICY_FILEが設定されている場合、GATEKEEPER_ROLESは無視されます。どちらも未設定の場合、全ユーザーがjunior_devロールとして扱われます。
GATEKEEPER_ROLES の書式
Section titled “GATEKEEPER_ROLES の書式”ロール名:ユーザー1,ユーザー2;ロール名:ユーザー3# 設定例export GATEKEEPER_ROLES="read_only:viewer1,viewer2;junior_dev:dev1,dev2;senior_dev:lead1;admin:dba_admin"GATEKEEPER_POLICY_FILE の使用
Section titled “GATEKEEPER_POLICY_FILE の使用”export GATEKEEPER_POLICY_FILE=/etc/gatekeeper/policy.jsonポリシーファイルの詳細な書き方は rbac-policy-guide.md を参照してください。
4. セキュリティ設定
Section titled “4. セキュリティ設定”管理APIの認証と接続レートリミットの設定です。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
ADMIN_API_KEY | (なし) | 管理API認証用のBearer Token。未設定かつ OIDC 未設定の場合は起動停止(後述 S-01 参照) |
GATEKEEPER_ADMIN_ALLOW_UNAUTH | (なし) | 1 を設定した場合のみ、ADMIN_API_KEY も OIDC も未設定の状態での起動を許可する(非推奨・開発用) |
GATEKEEPER_ADMIN_REQUIRE_TLS | (なし) | true にすると TLS cert/key 未設定時に起動を拒否(本番 fail-closed) |
GATEKEEPER_SESSION_MAX | 10000 | 同時保持する admin session の上限。login 連打での OOM 防御。到達時は 503 を返す |
GATEKEEPER_RATE_LIMIT | 100 | IP単位の1秒あたりの最大リクエスト数(Token Bucket方式) |
GATEKEEPER_RATE_BURST | 200 | バーストサイズ。瞬間的に許容するリクエスト数の上限 |
GATEKEEPER_RATE_BLOCK_SECONDS | 60 | レートリミット超過時のIPブロック秒数 |
⚠️ Security Warning: The
/debug/pprof/profiling endpoint is exposed on the admin API port. Always setADMIN_API_KEYin production to prevent unauthorized access to memory and CPU dumps.
Admin API TLS (S-10)
Section titled “Admin API TLS (S-10)”GATEKEEPER_TLS_CERT + GATEKEEPER_TLS_KEY が未設定で、かつ GATEKEEPER_LISTEN_ADDR
が loopback (127.0.0.1 / localhost / ::1) 以外の場合、起動時に CRITICAL 警告が
出ます。本番で admin API を外部ネットワークから到達可能にする場合は、以下のいずれかを
必ず実施してください:
- 推奨: TLS-terminating リバースプロキシ(nginx / Envoy / CDN)の背後に置く
- プロキシ本体で TLS を終端する(
GATEKEEPER_TLS_CERT+GATEKEEPER_TLS_KEY) - 外部到達を避ける(
GATEKEEPER_LISTEN_ADDR=127.0.0.1)
さらに強制したい場合は GATEKEEPER_ADMIN_REQUIRE_TLS=true を設定すると、TLS 未設定時に
起動を拒否 します(fail-closed)。
Admin API 認証の fail-closed 挙動(S-01)
Section titled “Admin API 認証の fail-closed 挙動(S-01)”v0 以降、ADMIN_API_KEY も OIDC(GATEKEEPER_OIDC_ISSUER)も未設定のまま起動しようとすると、Querycop は fatal ログを出して起動を拒否 します(fail-closed)。誤って無認証のまま本番公開する事故を防ぐためです。
どうしても無認証で起動したい場合(ローカル開発など)は、明示的に opt-in してください:
export GATEKEEPER_ADMIN_ALLOW_UNAUTH=1ただし GATEKEEPER_ADMIN_ALLOW_UNAUTH=1 を設定していても、GATEKEEPER_LISTEN_ADDR が外部から到達可能なアドレス(0.0.0.0、::、空文字、RFC1918 IP、公開 IP、解決不能ホスト名など)の場合は起動を拒否します。
- 許可される listen アドレス(無認証モード時):
127.0.0.1,::1,localhost - 拒否される listen アドレス:
0.0.0.0,::,192.168.x.x, 外部 IP, ホスト名
この制約を外す唯一の方法は、ADMIN_API_KEY または OIDC を設定することです。
# 管理API認証を有効化export ADMIN_API_KEY=my-secret-admin-token
# レートリミットのカスタマイズexport GATEKEEPER_RATE_LIMIT=50 # 1秒あたり50リクエストexport GATEKEEPER_RATE_BURST=100 # バースト100export GATEKEEPER_RATE_BLOCK_SECONDS=120 # 超過時2分間ブロックAPI認証の使用
Section titled “API認証の使用”ADMIN_API_KEY を設定すると、GET /(ダッシュボード)以外の全APIエンドポイントに Authorization ヘッダーが必要になります。
# 認証ありでリクエスト一覧を取得curl -H "Authorization: Bearer my-secret-admin-token" \ http://localhost:8080/requests5. データ保護
Section titled “5. データ保護”大容量リード遮断(Data Exfiltration防止)とデータマスキングの設定です。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_MAX_RESPONSE_MB | 100 | 単一レスポンスの最大サイズ(MB)。超過するとクエリが遮断されます |
GATEKEEPER_MAX_WINDOW_MB | 500 | 60秒間のスライディングウィンドウでの累積転送量上限(MB) |
GATEKEEPER_MASKING_FILE | (なし) | データマスキング設定ファイル(JSON)のパス |
# データガードの設定export GATEKEEPER_MAX_RESPONSE_MB=50 # 単一レスポンス50MBまでexport GATEKEEPER_MAX_WINDOW_MB=200 # 60秒間で200MBまで
# データマスキングの有効化export GATEKEEPER_MASKING_FILE=/etc/gatekeeper/masking.jsonマスキング設定ファイルの例
Section titled “マスキング設定ファイルの例”{ "rules": [ { "table": "users", "column": "email", "mask_type": "partial", "apply_to": ["junior_dev", "read_only"] }, { "table": "users", "column": "password_hash", "mask_type": "full" }, { "table": "payments", "column": "card_number", "mask_type": "partial", "exempt_from": ["admin"] }, { "table": "", "column": "ssn", "mask_type": "hash", "apply_to": ["junior_dev"] } ]}マスキングタイプ:
full- 値を完全にマスク(例:****)partial- 一部のみ表示(例:t***@example.com)hash- ハッシュ値に置換
6. JITアクセス
Section titled “6. JITアクセス”Just-In-Timeアクセス(申請 → 承認 → 一時ユーザー生成 → 自動失効)の設定です。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_JIT_MAX_TTL | 28800 | JITアクセスの最大有効期間(秒)。デフォルトは8時間(28800秒) |
# JITアクセスの最大TTLを4時間に制限export GATEKEEPER_JIT_MAX_TTL=14400承認待ちクエリの通知設定です。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_SLACK_WEBHOOK_URL | (なし) | Slack Incoming WebhookのURL。設定するとBlock Kit形式で承認リクエスト通知を送信 |
未設定の場合、通知はコンソール(標準出力)に出力されます。
export GATEKEEPER_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX8. Break-Glass(緊急アクセス)
Section titled “8. Break-Glass(緊急アクセス)”Break-Glass緊急アクセスモードの設定です。緊急時に通常のポリシーをバイパスし、全操作を記録します。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_BREAKGLASS_MAX_TTL | 3600 | Break-Glassセッションの最大有効期間(秒)。デフォルトは1時間 |
GATEKEEPER_BREAKGLASS_TOKEN | (なし) | Break-Glass 専用トークン。設定時は activate/deactivate で これ必須(ADMIN_API_KEY では通らない) |
# Break-Glassの最大TTLを30分に制限export GATEKEEPER_BREAKGLASS_MAX_TTL=1800全環境変数一覧
Section titled “全環境変数一覧”| 環境変数 | デフォルト | カテゴリ |
|---|---|---|
GATEKEEPER_LISTEN_PORT | 5432 | プロキシ |
GATEKEEPER_BACKEND_HOST | localhost | プロキシ |
GATEKEEPER_BACKEND_PORT | 5433 | プロキシ |
GATEKEEPER_API_PORT | 8080 | プロキシ |
GATEKEEPER_APPROVAL_TIMEOUT | 30 | プロキシ |
GATEKEEPER_DB_TYPE | postgresql | プロキシ |
AI_PROVIDER | openai | AI |
AI_API_KEY | (なし) | AI |
AI_ENDPOINT | (プロバイダー既定) | AI |
AI_MODEL | (プロバイダー既定) | AI |
GATEKEEPER_ROLES | (なし) | RBAC |
GATEKEEPER_POLICY_FILE | (なし) | RBAC |
ADMIN_API_KEY | (なし) | セキュリティ |
GATEKEEPER_ADMIN_ALLOW_UNAUTH | (なし) | セキュリティ |
GATEKEEPER_RATE_LIMIT | 100 | セキュリティ |
GATEKEEPER_RATE_BURST | 200 | セキュリティ |
GATEKEEPER_RATE_BLOCK_SECONDS | 60 | セキュリティ |
GATEKEEPER_MAX_RESPONSE_MB | 100 | データ保護 |
GATEKEEPER_MAX_WINDOW_MB | 500 | データ保護 |
GATEKEEPER_MASKING_FILE | (なし) | データ保護 |
GATEKEEPER_JIT_MAX_TTL | 28800 | JIT |
GATEKEEPER_JIT_PG_DSN | (なし) | JIT |
GATEKEEPER_JIT_PG_ROLE_READ_ONLY | qg_read_only | JIT |
GATEKEEPER_JIT_PG_ROLE_JUNIOR_DEV | qg_junior_dev | JIT |
GATEKEEPER_JIT_PG_ROLE_SENIOR_DEV | qg_senior_dev | JIT |
GATEKEEPER_JIT_PG_ROLE_ADMIN | qg_admin | JIT |
GATEKEEPER_SLACK_WEBHOOK_URL | (なし) | 通知 |
GATEKEEPER_BREAKGLASS_MAX_TTL | 3600 | Break-Glass |
GATEKEEPER_LISTEN_ADDR | 127.0.0.1 | プロキシ |
GATEKEEPER_TLS_CERT | (なし) | セキュリティ |
GATEKEEPER_TLS_KEY | (なし) | セキュリティ |
GATEKEEPER_LOG_FORMAT | text | 運用 |
GATEKEEPER_HTTP_RATE_LIMIT | 10 | セキュリティ |
GATEKEEPER_HTTP_RATE_BURST | 30 | セキュリティ |
GATEKEEPER_AUDIT_FILE | (なし) | 監査 |
GATEKEEPER_AUDIT_HMAC_KEY | (なし) | 監査(tamper evidence: 設定時は JSONL に HMAC hash chain を追記) |
GATEKEEPER_AUDIT_RETENTION_DAYS | (なし = license limit) | 監査(retention 窓 override、Enterprise FeatureAuditRetentionControls。詳細 §10.4) |
GATEKEEPER_WEBHOOK_FILE | (なし) | 通知 |
GATEKEEPER_CORS_ORIGIN | (なし) | セキュリティ |
GATEKEEPER_EXTERNAL_URL | (なし) | 通知 |
GATEKEEPER_ENABLE_PPROF | (なし) | デバッグ |
QUERYGUARD_LICENSE_KEY | (なし) | ライセンス token (env)。後方互換のため env 名は維持 |
GATEKEEPER_LICENSE_FILE | (なし) | ライセンス token のファイルパス。env 未設定時の fallback |
QUERYGUARD_LICENSE_PUBLIC_KEY | (同梱の公式公開鍵) | 検証用公開鍵 (env)。指定がなければビルド時 embed の公式鍵 |
GATEKEEPER_LICENSE_PUBLIC_KEY_FILE | (なし) | 公開鍵をファイルから読む場合のパス |
GATEKEEPER_LICENSE_HEARTBEAT_URL | tier 別(§11.4) | online activation server URL。paid Pro(trial でない Pro)は未設定でも公式 server に default-on、それ以外は空 = OFF。off / disabled / none で明示無効化 |
GATEKEEPER_LICENSE_HEARTBEAT_INTERVAL_SECONDS | 86400 | heartbeat 間隔 (24h) |
GATEKEEPER_LICENSE_HEARTBEAT_TIMEOUT_SECONDS | 30 | heartbeat per-ping timeout |
GATEKEEPER_LICENSE_OFFLINE_GRACE_SECONDS | 604800 | オフライン猶予 (7 日)。超過で Pro 機能 disable |
GATEKEEPER_OIDC_ISSUER | (なし) | SSO |
GATEKEEPER_OIDC_CLIENT_ID | (なし) | SSO |
GATEKEEPER_OIDC_ROLE_CLAIM | groups | SSO |
| (no env) | SafeTransport | SSO: OIDC discovery / token / JWKS fetch は SSRF 防御付き HTTP client を使い、private / link-local / IMDS 等へのリダイレクト接続を拒否 |
GATEKEEPER_OIDC_CLIENT_SECRET | (なし) | SSO |
GATEKEEPER_OIDC_REDIRECT_URI | (なし) | SSO |
GATEKEEPER_OIDC_ROLE_MAP | (なし) | SSO |
GATEKEEPER_SLACK_MODE | webhook | 通知 |
GATEKEEPER_SLACK_SIGNING_SECRET | (なし) | 通知 |
GATEKEEPER_CLUSTER_MODE | memory | クラスタ |
GATEKEEPER_REDIS_ADDR | (なし) | クラスタ |
GATEKEEPER_REDIS_PASSWORD | (なし) | クラスタ |
GATEKEEPER_REDIS_DB | 0 | クラスタ |
GATEKEEPER_CLUSTER_KEY_PREFIX | querycop | クラスタ |
GATEKEEPER_REDIS_KEY_PREFIX | (deprecated alias) | クラスタ |
GATEKEEPER_BILLING_PROVIDER | none | 課金 |
GATEKEEPER_STRIPE_API_KEY | (なし) | 課金 |
GATEKEEPER_STRIPE_METER_ID | (なし) | 課金 |
GATEKEEPER_BILLING_CUSTOMER_ID | default | 課金 |
GATEKEEPER_BILLING_BUFFER_SIZE | 1000 | 課金 |
GATEKEEPER_BREAKGLASS_TOKEN | (なし) | Break-Glass |
GATEKEEPER_PROXY_TLS_CERT | (なし) | プロキシTLS |
GATEKEEPER_PROXY_TLS_KEY | (なし) | プロキシTLS |
GATEKEEPER_SESSION_MAX | 1000 | セッション記録 |
GATEKEEPER_SESSION_FILE | (なし) | セッション永続化 |
9. QueryGuard → Querycop リネームに伴う移行ガイド
Section titled “9. QueryGuard → Querycop リネームに伴う移行ガイド”対象: プロダクト名を QueryGuard から Querycop にリネームしました。既存デプロイで wire-level に使われていた名前空間も同時に更新されています。旧名を引き続き使う互換手段を用意していますが、deprecation 期間中のみ有効です。
9.1 Redis クラスタ key prefix
Section titled “9.1 Redis クラスタ key prefix”| 項目 | 旧デフォルト | 新デフォルト | 互換性 |
|---|---|---|---|
| Redis key prefix | queryguard:* | querycop:* | 既存 queryguard を使い続けるには GATEKEEPER_CLUSTER_KEY_PREFIX=queryguard を設定 |
| Pub/Sub channel prefix | queryguard:resolve:* | querycop:resolve:* | 同上(prefix は同じ env 変数で統一される) |
既存デプロイの扱い:
- Redis に
queryguard:*キーが残っている環境では、移行期間中はGATEKEEPER_CLUSTER_KEY_PREFIX=queryguardを設定して旧動作を維持してください。 - 新規デプロイはデフォルト (
querycop) を使用してください。 GATEKEEPER_REDIS_KEY_PREFIXは deprecated alias として引き続き認識されます (値が空でなければGATEKEEPER_CLUSTER_KEY_PREFIXより低い優先度で採用)。次メジャーで削除予定。
移行推奨手順 (クラスタ稼働中のローリング更新):
- 1 ノードを
GATEKEEPER_CLUSTER_KEY_PREFIX=queryguardで新バージョン起動 → 従来の pending セッション継続 - 全ノード更新完了後、一度サービス停止できるメンテウィンドウで
querycopに切り替え - 旧 key は Redis 側で
DEL queryguard:*や TTL 失効で破棄
9.2 Slack interactive buttons の action_id
Section titled “9.2 Slack interactive buttons の action_id”| 項目 | 旧 | 新 |
|---|---|---|
| block_id | queryguard_actions | querycop_actions |
| approve action_id | queryguard_approve | querycop_approve |
| reject action_id | queryguard_reject | querycop_reject |
互換性: /slack/interactions エンドポイントは 旧 action_id も引き続き受け付けます。Slack に残る旧メッセージのボタンをクリックしても正しく動作します。新規送信メッセージは querycop_* で送られます。
9.3 Webhook payload
Section titled “9.3 Webhook payload”| 項目 | 旧 | 新 |
|---|---|---|
source フィールド | "queryguard" | "querycop" |
User-Agent | QueryGuard-Webhook/1.0 | Querycop-Webhook/1.0 |
影響: 外部システム側で source == "queryguard" をハードコードしている場合は "querycop" に更新してください。移行期間中の両対応は 呼び出し側で実装する必要があります (Querycop 本体は新値のみ送信)。
9.4 Helm チャートのリネーム
Section titled “9.4 Helm チャートのリネーム”Helm チャートのディレクトリ・チャート名・テンプレートのリソース名を
queryguard から querycop にリネームしました。
| 項目 | 旧 | 新 | 互換性 |
|---|---|---|---|
| チャートディレクトリ | charts/queryguard/ | charts/querycop/ | パス参照を更新。レジストリ配布はないのでローカルパス参照のみ影響。旧パスには移行先を案内する tombstone README を残置 |
Chart 名 (Chart.yaml) | queryguard | querycop | helm install の release 名は任意なので影響なし |
| リソース名 | <release>-queryguard | <release>-querycop | 既存リリースの in-place upgrade には --set nameOverride=queryguard が必須 |
| selector label | app: queryguard | app: querycop | Deployment の selector は immutable。nameOverride=queryguard を渡さないと helm upgrade が Kubernetes に拒否される |
image.repository デフォルト | queryguard (誤り) | querycop | 公開イメージ名は元々 querycop。旧デフォルトは存在しないイメージを pull する bug だった |
cluster.redis.keyPrefix デフォルト | queryguard | querycop | §9.1 の code デフォルトと一致。既存 queryguard:* キーがある環境は --set cluster.redis.keyPrefix=queryguard を設定 |
新規デプロイ:
helm install <release> ./charts/querycop \ --set backend.host=my-postgres \ --set api.adminApiKey=your-secret-key既存デプロイの in-place upgrade (旧 queryguard 名で稼働中):
helm upgrade <release> ./charts/querycop \ --set nameOverride=queryguard \ --set cluster.redis.keyPrefix=queryguard # Redis backend を使う場合のみnameOverride=queryguard を渡すと、レンダリングされるリソース名
(<release>-queryguard) と selector label (app: queryguard) が
リネーム前と byte-identical になり、Deployment selector の
immutability 制約に抵触せず in-place upgrade が成立します。
クリーンな新名称への移行: メンテナンス枠で helm uninstall →
helm install してください。persistence.auditFile を使っている場合は
PVC の retain policy に注意 (デフォルトの ReadWriteOnce PVC は
release 削除時に削除され得ます)。
10. 監査ログ
Section titled “10. 監査ログ”監査ログは 2 つの独立したシンク に書き込まれます。それぞれ持つフィールドと API での見え方が違うので、運用設計時に意識する必要があります。
10.1 シンクの種類
Section titled “10.1 シンクの種類”| シンク | 永続化 | フィールド | 設定 |
|---|---|---|---|
メモリストア (audit.MemoryStore) | プロセス内 (最大 10,000 件、再起動で消失) | 標準フィールドのみ | デフォルトで常に有効 |
JSONL ファイルログ (audit.FileStore) | 永続 | 標準フィールド + prev_hash / hash(HMAC chain 設定時) | GATEKEEPER_AUDIT_FILE で有効化 |
| Webhook 連携 | 外部基盤 (Datadog / Splunk / 自前) で永続 | 標準フィールド | GATEKEEPER_WEBHOOK_FILE |
重要: REST API
GET /auditは メモリストアからのみ 取得します。HMAC chain のprev_hash/hashは JSONL ファイルにのみ 追記されるため、API レスポンスには含まれません。改ざん検知の検証はファイルを直接読む別ツールで行ってください(pkg/audit.VerifyChainを使えるオフライン検証ツールが組み込み可能)。
10.2 HMAC hash chain (S-07, tamper evidence)
Section titled “10.2 HMAC hash chain (S-07, tamper evidence)”GATEKEEPER_AUDIT_HMAC_KEY を設定すると、JSONL の各エントリに以下が追記されます:
{ "id":"...","timestamp":"...","event_type":"approved", "prev_hash":"<前 entry の hash、最初は空>", "hash":"<HMAC-SHA256(key, prev_hash || canonical(entry))>"}pkg/audit.VerifyChain(reader, key) で先頭から順に検証でき、改ざん箇所のインデックスを FirstBadIndex で返します。
HMAC キーの管理: HMAC キーが Querycop と同居していると、ホスト侵害時に攻撃者が改ざん + 再ハッシュできるため、tamper evidence は半減します。本番では Vault / KMS / HSM など別ストアでキーを管理してください。
10.3 永続化の推奨
Section titled “10.3 永続化の推奨”本番環境では以下を併用することを推奨します:
- JSONL + HMAC: ファイル保管 (
GATEKEEPER_AUDIT_FILE+GATEKEEPER_AUDIT_HMAC_KEY) で 改ざん検知付きの local trail を残す - Webhook 連携: 外部 SIEM / log aggregator にリアルタイム転送し、ホスト障害時の保証を持たせる
- Slack 通知:
GATEKEEPER_SLACK_WEBHOOK_URLで重要イベントを人間に即時通知
将来のバージョンでは、SQLite / PostgreSQL 連携による監査ログの直接永続化を予定しています。
10.4 Retention enforcement
Section titled “10.4 Retention enforcement”audit_retention_days limit(entitlements.md §4)が
実際に enforce されます。retention 窓より古い audit entry / closed
session が JSONL ファイルから prune されます。
⚠️ Pro デプロイへの behavior change: Pro の license limit は 30 日です。retention enforcement に対応したバージョンに上げると、永続 audit file (
GATEKEEPER_AUDIT_FILE) / session file (GATEKEEPER_SESSION_FILE) の 30 日より古いレコードは初回起動時に prune されます。長期保持が 必要な場合は upgrade 前にファイルを退避するか、retention 窓を契約で 設定できる Enterprise(FeatureAuditRetentionControls)を検討して ください。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
GATEKEEPER_AUDIT_RETENTION_DAYS | (なし = license limit に従う) | Retention 窓の override (FeatureAuditRetentionControls, Enterprise)。0 = prune しない(Enterprise の opt-out)。非 Enterprise では無視され license limit (Pro 30 日) が適用される (起動時に INFO ログ) |
動作:
- 実行タイミング: 初回 prune は proxy がトラフィックを受け付ける前 に同期実行(アップグレード直後の大きな backlog prune がクエリを 停止させない)。以降は 24 時間ごとに background 実行。
- Fail-safe: パース不能な行・timestamp が zero の entry・
ended_atが無い session は 削除しない(曖昧なものは残す)。書き込みは temp file + atomic rename で、エラー時は元ファイル無傷。 - 自己監査: prune 実行のたびに
retention_pruneevent が audit log に記録される(何件削除・cutoff・HMAC chain mode では削除セグメント 最終 entry の hash を forensic anchor として含む)。コンプライアンス 証跡の削除自体が証跡として残ります。 - HMAC chain との関係: prune 後、生存 entry は genesis から
re-chain され、
retention_pruneevent が chain 末尾に連結されます。VerifyChainは prune 後のファイルでも pass します。chain の脅威 モデルは「鍵を持たない者による改ざんの検知」であり、鍵保持者 (Querycop 自身) による prune は in-chain の prune event で可視化 されます — 黙って消えるのではなく、消したことが記録されます。 - Runtime re-check: retention 窓は実行のたびに live license から
再解決されます。Enterprise → Pro の heartbeat downgrade で
GATEKEEPER_AUDIT_RETENTION_DAYSの override は失効し、次回実行から Pro の 30 日 cap が適用されます。
11. ライセンス(Wowza 流アクティベーション)
Section titled “11. ライセンス(Wowza 流アクティベーション)”Querycop は Apache 2.0 OSS の上に closed-source 寄りの Pro/Enterprise tier を載せるモデル。 license token (Ed25519 署名) で機能 gating + 30 日 trial + online activation (heartbeat) を提供。
11.1 token の解決順 (本体側)
Section titled “11.1 token の解決順 (本体側)”querycop 起動時、license token は以下の順で解決されます:
QUERYGUARD_LICENSE_KEY(env、最優先・後方互換のため env 名は維持)GATEKEEPER_LICENSE_FILEが指すパス (例:/etc/querycop/license.token)<UserConfigDir>/querycop/license.token- Windows:
%AppData%\querycop\license.token - macOS:
~/Library/Application Support/querycop/license.token - Linux:
~/.config/querycop/license.token
- Windows:
$HOME/.querycop/license.token(UserConfigDir 解決失敗時の fallback)
これにより querycop-cli trial start で取得した token は、追加設定なしで querycop 起動時に自動 pickup されます。
11.2 公開鍵の解決順
Section titled “11.2 公開鍵の解決順”QUERYGUARD_LICENSE_PUBLIC_KEY(env)GATEKEEPER_LICENSE_PUBLIC_KEY_FILEファイル- ビルド時 embedded な公式公開鍵 (GoReleaser が ldflags で注入。dev build では空)
11.3 Trial 取得 (1 コマンド)
Section titled “11.3 Trial 取得 (1 コマンド)”# → 30 日 Pro trial token を ~/.config/querycop/license.token に保存querycop # ↑が自動 pickup されて Pro 起動11.4 オンライン activation (heartbeat)
Section titled “11.4 オンライン activation (heartbeat)”GATEKEEPER_LICENSE_HEARTBEAT_URL を設定すると、24 時間ごとに license server に
ping を打ち、revocation があれば即降格 (Pro 機能 disable)、network 不通時は
GATEKEEPER_LICENSE_OFFLINE_GRACE_SECONDS (default 7 日) 以内なら継続、超過で降格。
default の挙動: paid Pro license(is_trial=false の Pro)
では未設定でも https://api.querycop.com/v1/license/heartbeat に default-on
になりました。paid Pro は phone-home tier で、返金・支払い停止の revocation は
heartbeat 経由でのみ届くためです。trial / Community / Enterprise は従来どおり
未設定 = OFF。ネットワーク制限環境で heartbeat を切る場合は
GATEKEEPER_LICENSE_HEARTBEAT_URL=off(disabled / none も可)を明示して
ください — 設定せず不通のままだと offline grace(7 日)超過で Community に
降格します。offline / air-gapped 運用の正式経路は Enterprise の Offline
License 機能です。
| Env | Default |
|---|---|
GATEKEEPER_LICENSE_HEARTBEAT_URL | paid Pro: 公式 server に default-on / それ以外: 空 = OFF。off で明示無効化 |
GATEKEEPER_LICENSE_HEARTBEAT_INTERVAL_SECONDS | 86400 (24h) |
GATEKEEPER_LICENSE_HEARTBEAT_TIMEOUT_SECONDS | 30 |
GATEKEEPER_LICENSE_OFFLINE_GRACE_SECONDS | 604800 (7 days) |
11.4.1 Paid license の取得(license claim)
Section titled “11.4.1 Paid license の取得(license claim)”Lemon Squeezy で Pro を購入すると、レシート記載の注文番号と購入時メールで token を引き換えられます:
querycop-cli license claim --order=<注文番号> --email=<購入時メール># → token を ~/.config/querycop/license.token に保存(--no-save で表示のみ)| Env | Default | 説明 |
|---|---|---|
GATEKEEPER_LICENSE_CLAIM_URL | https://api.querycop.com/v1/license/claim | claim エンドポイントの上書き |
paid token は machine 非束縛(per-team)で、有効期間は発行から 365 日。 月次の支払い状態は heartbeat の revocation で enforcement されます(§11.4)。
MachineID binding:
querycop-cli trial startで発行される token は 当該マシンの fingerprint (sha256 of hostname + sorted MACs + GOOS + GOARCH) に bind されています。別ホストにコピーしても起動時 validation で失敗します。
11.5 Dashboard UX
Section titled “11.5 Dashboard UX”GET /license で license status (tier / valid / is_trial / days_until_expiry /
features) を返す。Dashboard は header に tier badge + Trial countdown +
Upgrade CTA を表示する。
license-disabled な Pro / Enterprise タブ
(JIT, Metrics 等) は 🔒 lock card に置き換わり、“Upgrade to Pro” /
“Contact sales” の CTA を表示する (locked タブはバックエンド API を呼ばないので
console / audit に余計な 403 が出ない)。Heartbeat downgrade は 60 秒以内に UI に
反映され、リロード不要。/license fetch が失敗した場合は fail-closed で
“License check failed (retrying…)” の badge を表示し、すべての gated タブを
locked 表示にする (isFeatureEnabled が null safe で false を返すため)。
11.6 AI quota と static degrade
Section titled “11.6 AI quota と static degrade”Pro / Community 共通で ai_requests_per_day の cap がある (Community 100 / Pro
5,000 / Enterprise unlimited)。cap を超えても proxy traffic は止めない:
pkg/ai/tracked.go が外部 AI 呼び出しを止めて static
rule-based scorer (pkg/ai/static.go) に degrade する設計。詳細は
docs/entitlements.md §7.4 (License Over-Limit Policy)
を参照。env 変数の追加は無し (cap は license claim の Limits.AIRequestsPerDay
で配信)。