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:
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_HOSTSexactly or an explicit*.example.comwildcard; - 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:
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.