Skip to content

Operations: webhooks

BucketReef can notify external systems when application control-plane events occur. Super-administrators configure webhook endpoints from **Admin > Settings

Webhooks**. Browser object data-plane activity such as uploads, downloads, object listing, and object deletion is intentionally excluded from this mechanism.

Configure an endpoint

Each endpoint defines:

  • a display name and target HTTP(S) URL;
  • an enabled/disabled state;
  • one signing secret, generated by BucketReef and shown only when the endpoint is created or the secret is rotated;
  • an event filter containing either * for all current and future webhook events or an explicit set of event types.

The Admin editor exposes the current event catalogue and groups it by product area. It includes audited Admin, Manager, Portal, Browser configuration, Ceph Admin, Storage Ops, authentication, and security actions, plus dedicated migration, endpoint-health, quota-threshold, and webhook-test events.

An endpoint imported from the former bucket-migration-specific callback field is created disabled and without a signing secret. Open it in **Admin > Settings

Webhooks**, generate a signing secret, review the destination and event subscription, then enable it when the receiving service is ready.

Request payload

Every request body is JSON with this stable envelope:

{
  "id": "5d7ce2eb-2ba5-4f51-ae3d-f99965201a54",
  "type": "audit.manager.create_bucket",
  "version": 1,
  "occurred_at": "2026-09-26T08:30:00+00:00",
  "data": {}
}

id identifies the logical event. One logical event can create multiple deliveries when several endpoints subscribe to it. data varies by event type and is sanitized through the same sensitive-data boundary used for application audit metadata.

BucketReef sends these headers:

Header Purpose
X-BucketReef-Event Event type from the payload.
X-BucketReef-Delivery Unique delivery identifier for idempotence.
X-BucketReef-Timestamp Unix timestamp used for signature verification.
X-BucketReef-Signature v1=<hex> HMAC-SHA256 signature.

Verify the signature

The signature covers the timestamp, a literal period, and the exact raw request body:

HMAC-SHA256(signing_secret, X-BucketReef-Timestamp + "." + raw_body)

Compare the hexadecimal result with the value after v1= in X-BucketReef-Signature using a constant-time comparison. Verify the signature before parsing or transforming the JSON body. Consumers should also reject timestamps outside their accepted replay window.

Delivery and idempotence

Webhook delivery is at-least-once. A successful 2xx response marks the delivery complete. Network errors, 408, 425, 429, and 5xx responses are retried with exponential backoff up to WEBHOOK_MAX_ATTEMPTS; a valid Retry-After response header can extend the next delay up to WEBHOOK_RETRY_MAX_SECONDS. Other HTTP failures are terminal. HTTP redirects are not followed.

Because an external service can receive the same logical delivery more than once, store or otherwise deduplicate X-BucketReef-Delivery. Recent attempts and their status are visible on the endpoint detail page. Terminal delivery history is retained for WEBHOOK_RETENTION_DAYS days; 0 disables automatic purging.

Outbound security

BucketReef validates a webhook target both when it is saved and immediately before each delivery. In production:

  • the target must use HTTPS unless WEBHOOK_ALLOW_PRIVATE_TARGETS=true;
  • the hostname must match WEBHOOK_ALLOWED_HOSTS exactly or an explicit *.example.com wildcard;
  • DNS resolution is checked against the private/local target policy;
  • redirects remain disabled, so a receiver cannot redirect BucketReef to a different target.

Keep the allowlist narrow and prefer dedicated webhook receiver hostnames. WEBHOOK_ALLOW_PRIVATE_TARGETS=true is intended for explicitly approved internal receivers; it does not bypass the production hostname allowlist.

Before enabling the production profile, run:

cd backend
python -m app.scripts.preflight_outbound_targets

The preflight reports uncovered hostnames without printing complete webhook URLs or query strings.

Runtime settings

Variable Default Purpose
WEBHOOK_WORKER_ENABLED true Allow the durable delivery worker on an Admin-capable backend. Split user and ceph-admin-high-security profiles never dispatch.
WEBHOOK_POLL_INTERVAL_SECONDS 1.0 Delay between durable queue scans.
WEBHOOK_WORKER_LEASE_SECONDS 120 Global dispatcher lease used to coordinate backend replicas.
WEBHOOK_TIMEOUT_SECONDS 5.0 HTTP delivery timeout.
WEBHOOK_ALLOWED_HOSTS [] Production target hostname allowlist.
WEBHOOK_ALLOW_PRIVATE_TARGETS false Permit explicitly allowlisted private/local targets and HTTP in production.
WEBHOOK_WORKERS 4 Maximum parallel delivery workers.
WEBHOOK_MAX_ATTEMPTS 8 Maximum delivery attempts.
WEBHOOK_RETRY_INITIAL_SECONDS 30 Initial retry delay.
WEBHOOK_RETRY_MAX_SECONDS 3600 Retry backoff and Retry-After cap.
WEBHOOK_RETENTION_DAYS 30 Terminal delivery retention; 0 disables purge.

For one upgrade window, the legacy migration settings BUCKET_MIGRATION_WEBHOOK_TIMEOUT_SECONDS, BUCKET_MIGRATION_WEBHOOK_ALLOW_PRIVATE_TARGETS, BUCKET_MIGRATION_WEBHOOK_ALLOWED_HOSTS, and BUCKET_MIGRATION_WEBHOOK_WORKERS remain fallback aliases when the matching new WEBHOOK_* value is not explicitly configured. New values take precedence. BUCKET_MIGRATION_WEBHOOK_QUEUE_SIZE is accepted only for compatibility and is ignored because deliveries now use the database-backed queue.

In a multi-backend deployment, every backend may enqueue matching events into the shared PostgreSQL queue. Only an Admin-capable runtime (full, admin, or admin-no-ceph-admin) may acquire the global dispatcher lease and perform the outbound HTTP delivery. The user and ceph-admin-high-security profiles keep WEBHOOK_WORKER_ENABLED=false; they therefore do not need webhook-target egress or WEBHOOK_ALLOWED_HOSTS solely for delivery. Configure the webhook allowlist and any NetworkPolicy egress on the Admin release that owns dispatch.

Operational guidance

Use the endpoint's Send test action after configuring or rotating its secret. A test creates a normal durable delivery with event type system.webhook.test, so it exercises the same URL validation, signing, worker, retry, and delivery-history path as production events.

If delivery stops, check the endpoint's recent delivery rows first. A terminal allowlist/private-target error indicates that the runtime policy no longer allows the stored destination. Revalidate DNS, TLS, the receiver's response, and the production allowlist before retrying with a test delivery.