-
Notifications
You must be signed in to change notification settings - Fork 131
Description
Problem
The approval webhook endpoint (POST /api/v1/webhooks/approval-response) currently relies on the global API key authentication middleware. This creates two issues:
-
API key exposure — External approval services must embed the control plane's API key in the webhook callback URL (e.g., as a query parameter), which gets logged in access logs, stored in databases, and visible in HTTP server logs.
-
Requires internet-reachable control plane — The webhook callback is a direct HTTP POST from the external approval service to the control plane. If the CP is behind a firewall or VPN, the callback can't reach it. This undermines the connector architecture which is specifically designed for isolated control planes.
Current State
- The webhook handler already has full HMAC-SHA256 signature verification implemented (
verifySignatureinwebhook_approval.go) - It supports multiple signature formats:
t=timestamp,v1=signature, raw hex, andsha256=prefixed - The
ApprovalWebhookHandleralready accepts awebhookSecretparameter from config (config.AgentField.Approval.WebhookSecret) - The global auth middleware already supports
SkipPathsfor bypassing API key auth on specific endpoints
Proposed Solution
Phase 1: HMAC-only auth for webhook endpoint
- Add
/api/v1/webhooks/approval-responseto the global auth middleware'sSkipPathsso it bypasses API key auth - Require the
approval.webhook_secretconfig to be set when the webhook endpoint is active - The webhook handler already verifies signatures — just need to make it mandatory (currently it's optional: skipped when
webhookSecret == "") - Agents pass the
webhook_secretto the external approval service when creating approval requests, so it can sign callbacks
This way:
- No API key in URLs or stored externally
- Webhook is authenticated via cryptographic signature
- Each approval service can have its own webhook secret
Phase 2: Connector-routed approval callbacks (future)
For fully isolated control planes that aren't internet-reachable:
- Route approval callbacks through the existing connector WebSocket channel (SaaS → connector → CP)
- Add an
approval_responsecommand type to the connector protocol - The external approval service sends the callback to the SaaS platform, which forwards it through the connector to the CP
- No public CP URL needed at all
Files
control-plane/internal/handlers/webhook_approval.go— webhook handler with existing HMAC verificationcontrol-plane/internal/server/middleware/auth.go— global API key auth withSkipPathssupportcontrol-plane/internal/server/server.go:1243— webhook route registrationcontrol-plane/internal/config/config.go—Approval.WebhookSecretconfig field
Context
Discovered during deployment where the control plane had API key auth enabled. The approval service couldn't call the webhook endpoint without the API key, leading to the workaround of embedding the API key as a query parameter in the webhook URL.