Dynamic, scoped API keys (+ restore cmd/server entrypoint) #1
Reference in New Issue
Block a user
Delete Branch "feat/dynamic-scoped-api-keys"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Adds a dynamic, self-managed API-key store so new consumers can be added at runtime without a rebuild, and limits each key to specific calls via scopes.
X-API-Keyis validated against the static Infisical keys and active rows inadmin.api_keys(SHA-256 hashes only).{ldap:read}). Required scope is derived per-request from the path's first segment + method (GET→read, else write);apikeys:adminguards the management routes. Enforced byScopeEnforce.*scope — no regression for existing consumers (skill-server, voice-agent, synapse-hub, gsc-my).POST/GET/DELETE /api/v1/admin/api-keys(bootstrapped by any existing valid key).EnsureSchemais existence-first (to_regclass) so a least-privilege DB role starts cleanly when the table is provisioned out-of-band; startup is non-fatal if the store is unavailable.Also: restore
cmd/server/main.goThe repo was missing its entrypoint — the
.gitignoreserverpattern (for the built binary) also matchedcmd/server/, so the initial import silently dropped it. Anchoredserverandgsc-ops-apito the repo root and force-added the file. The repo is now buildable from a clean clone.Deployed & verified
Binary
1.1.0live on fihelvop01.admin.api_keysprovisioned ingsc_core,SELECT/INSERT/UPDATEgranted togsc_ops_api. End-to-end with a scopedgsc_adminkey ({ldap:read}):GET /ldap/users→ 200;GET /dns/zones→ 403;POST /ldap/users→ 403. Existing consumers unaffected.🤖 Generated with Claude Code
Validate X-API-Key against a DB-backed, self-managed key store in addition to the static Infisical keys, so new consumers (e.g. gsc_admin) no longer require a rebuild. Keys carry scopes (e.g. {ldap:read}); the required scope is derived per-request from path + method and enforced by ScopeEnforce. Static Infisical keys keep an implicit wildcard scope (no regression). - service/apikey.go: DB store (admin.api_keys, SHA-256 hashes only), 30s validation cache, generate/list/revoke. EnsureSchema is existence-first (to_regclass) so a least-privilege DB role starts cleanly when the table is provisioned out-of-band; startup is non-fatal if the store is absent. - handler/apikeys.go + routes: POST/GET/DELETE /api/v1/admin/api-keys. - middleware/apikey.go: APIKeyWithValidator + Principal + ScopeEnforce. - pkg/types/scopes.go: scope vocabulary + matching. - migrations/002_api_keys.sql. Also restore cmd/server/main.go, which the `.gitignore` `server` pattern was silently excluding (it matched cmd/server/); anchored that pattern and `gsc-ops-api` to the repo root so only the built binaries are ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>