Dynamic, scoped API keys (+ restore cmd/server entrypoint) #1

Merged
supportgsc merged 1 commits from feat/dynamic-scoped-api-keys into main 2026-06-01 09:33:18 +00:00
Owner

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-Key is validated against the static Infisical keys and active rows in admin.api_keys (SHA-256 hashes only).
  • Keys carry scopes (e.g. {ldap:read}). Required scope is derived per-request from the path's first segment + method (GET→read, else write); apikeys:admin guards the management routes. Enforced by ScopeEnforce.
  • Static Infisical keys keep an implicit * scope — no regression for existing consumers (skill-server, voice-agent, synapse-hub, gsc-my).
  • New endpoints: POST/GET/DELETE /api/v1/admin/api-keys (bootstrapped by any existing valid key).
  • 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 unavailable.

Also: restore cmd/server/main.go

The repo was missing its entrypoint — the .gitignore server pattern (for the built binary) also matched cmd/server/, so the initial import silently dropped it. Anchored server and gsc-ops-api to the repo root and force-added the file. The repo is now buildable from a clean clone.

Deployed & verified

Binary 1.1.0 live on fihelvop01. admin.api_keys provisioned in gsc_core, SELECT/INSERT/UPDATE granted to gsc_ops_api. End-to-end with a scoped gsc_admin key ({ldap:read}): GET /ldap/users → 200; GET /dns/zones → 403; POST /ldap/users → 403. Existing consumers unaffected.

🤖 Generated with Claude Code

## 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-Key` is validated against the static Infisical keys **and** active rows in `admin.api_keys` (SHA-256 hashes only). - Keys carry **scopes** (e.g. `{ldap:read}`). Required scope is derived per-request from the path's first segment + method (GET→read, else write); `apikeys:admin` guards the management routes. Enforced by `ScopeEnforce`. - Static Infisical keys keep an implicit `*` scope — **no regression** for existing consumers (skill-server, voice-agent, synapse-hub, gsc-my). - New endpoints: `POST/GET/DELETE /api/v1/admin/api-keys` (bootstrapped by any existing valid key). - `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 unavailable. ## Also: restore `cmd/server/main.go` The repo was missing its entrypoint — the `.gitignore` `server` pattern (for the built binary) also matched `cmd/server/`, so the initial import silently dropped it. Anchored `server` and `gsc-ops-api` to the repo root and force-added the file. **The repo is now buildable from a clean clone.** ## Deployed & verified Binary `1.1.0` live on fihelvop01. `admin.api_keys` provisioned in `gsc_core`, `SELECT/INSERT/UPDATE` granted to `gsc_ops_api`. End-to-end with a scoped `gsc_admin` key (`{ldap:read}`): `GET /ldap/users` → 200; `GET /dns/zones` → 403; `POST /ldap/users` → 403. Existing consumers unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
supportgsc added 1 commit 2026-06-01 09:23:26 +00:00
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>
supportgsc merged commit 2de3fb0ead into main 2026-06-01 09:33:18 +00:00
supportgsc deleted branch feat/dynamic-scoped-api-keys 2026-06-01 09:33:22 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: GoSec_Cloud/gsc-ops-api#1