Webhooks & Events

Event-driven automation with webhooks

Rackd provides a webhook system for event-driven automation and external integrations.

Overview

Webhooks allow external systems to receive real-time notifications when events occur in Rackd. This enables:

  • Automated workflows triggered by device changes
  • Integration with monitoring and ticketing systems
  • Real-time sync with CMDBs and asset management tools
  • Custom alerting and notification pipelines

Webhook Model

FieldTypeDescription
idstringUnique identifier
namestringDescriptive name
urlstringTarget URL for webhook delivery
secretstringSecret for HMAC signature (write-only)
events[]stringList of subscribed events
enabledboolWhether webhook is active
descriptionstringOptional description
headersmapCustom HTTP headers
timeout_secondsintRequest timeout (default: 10)
retry_countintNumber of retries on failure (default: 3)
created_attimestampCreation timestamp
updated_attimestampLast update timestamp

Supported Events

Device Events

EventDescription
device.createdNew device added
device.updatedDevice properties changed
device.deletedDevice removed
device.promotedDevice promoted from discovered

Network Events

EventDescription
network.createdNew network created
network.updatedNetwork properties changed
network.deletedNetwork removed

Discovery Events

EventDescription
discovery.startedDiscovery scan started
discovery.completedDiscovery scan completed
discovery.device_foundNew device discovered

Conflict Events

EventDescription
conflict.detectedIP conflict detected
conflict.resolvedConflict resolved

Pool Events

EventDescription
pool.utilization_highPool utilization exceeds threshold

Webhook Delivery

Request Format

Webhooks are delivered as HTTP POST requests with JSON payloads:

POST /webhook-endpoint HTTP/1.1
Content-Type: application/json
X-Rackd-Event: device.created
X-Rackd-Delivery: del-abc123
X-Rackd-Signature: sha256=abc123...
X-Rackd-Timestamp: 1709000000

{
  "event": "device.created",
  "delivery_id": "del-abc123",
  "timestamp": "2024-02-27T10:00:00Z",
  "data": {
    "id": "dev-123",
    "hostname": "server01.example.com",
    "ip_address": "192.168.1.10",
    "status": "active"
  }
}

Signature Verification

Each webhook includes an HMAC-SHA256 signature in the X-Rackd-Signature header:

import hmac
import hashlib

def verify_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Retry Policy

Failed deliveries are retried with exponential backoff:

  • Retry intervals: 1m, 5m, 15m, 1h, 6h
  • Maximum retry count configurable per webhook
  • After max retries, delivery is marked as failed

Security & SSRF Protection

Rackd implements robust protection against Server-Side Request Forgery (SSRF) and DNS rebinding attacks to ensure the webhook system cannot be exploited to access restricted internal endpoints:

  • Loopback Blocking: Connections to 127.0.0.0/8 and ::1 are blocked
  • Unspecified Blocking: Connections to 0.0.0.0 and :: are blocked
  • Cloud Metadata Blocking: Connections to the standard 169.254.x.x link-local range used by AWS/GCP metadata services are blocked
  • DNS Rebinding Prevention: Hostnames are resolved first, and Rackd connects strictly to the pre-verified IP address

Note: Standard private intranet subnets (e.g. 10.x.x.x, 192.168.x.x) are permitted to allow legitimate communication with other internal services on your network.

API Endpoints

List Webhooks

GET /api/webhooks

Get Webhook

GET /api/webhooks/{id}

Create Webhook

POST /api/webhooks

Request body:

{
  "name": "Slack Notifications",
  "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
  "secret": "my-webhook-secret",
  "events": ["device.created", "device.deleted", "conflict.detected"],
  "enabled": true,
  "headers": {
    "X-Custom-Header": "value"
  }
}

Update Webhook

PUT /api/webhooks/{id}

Delete Webhook

DELETE /api/webhooks/{id}

Ping Webhook

POST /api/webhooks/{id}/ping

Sends a test delivery to verify webhook configuration.

List Deliveries

GET /api/webhooks/{id}/deliveries

Returns delivery history with status and response details.

CLI Commands

List Webhooks

rackd webhook list

Get Webhook

rackd webhook get --id wh-abc123

Create Webhook

rackd webhook create \
  --name "Slack Notifications" \
  --url "https://hooks.slack.com/services/XXX/YYY/ZZZ" \
  --secret "my-secret" \
  --events "device.created,device.deleted" \
  --enabled

Update Webhook

rackd webhook update \
  --id wh-abc123 \
  --events "device.created,device.deleted,device.updated"

Delete Webhook

rackd webhook delete --id wh-abc123

Test Webhook

rackd webhook ping --id wh-abc123

List Available Events

rackd webhook events

Web UI

Access webhook management at /webhooks in the web interface.

Features

  • List View: Table of all webhooks with status indicators
  • Delivery History: View delivery attempts and responses
  • Event Selection: Multi-select for subscribed events
  • Test Delivery: Ping button to verify configuration
  • Secret Management: Secure secret input (never displayed after save)

RBAC Permissions

PermissionDescription
webhook:listView list of webhooks
webhook:readView webhook details (excludes secret)
webhook:createCreate new webhooks
webhook:updateModify existing webhooks
webhook:deleteDelete webhooks

Integration Examples

Slack Integration

rackd webhook create \
  --name "Slack - Device Alerts" \
  --url "https://hooks.slack.com/services/T00/B00/XXX" \
  --events "device.created,device.deleted,conflict.detected"

Generic Webhook Handler

from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "your-secret-key"

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    # Verify signature
    signature = request.headers.get('X-Rackd-Signature', '')
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        request.data,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(f"sha256={expected}", signature):
        return 'Invalid signature', 401

    # Process event
    event = request.json
    print(f"Received: {event['event']}")

    # Handle based on event type
    if event['event'] == 'device.created':
        handle_new_device(event['data'])

    return jsonify({'status': 'ok'}), 200

if __name__ == '__main__':
    app.run(port=5000)

PowerShell Handler

# webhook-handler.ps1
param(
    [Parameter(Mandatory=$true)]
    [string]$Payload
)

$event = $Payload | ConvertFrom-Json

switch ($event.event) {
    "device.created" {
        Write-Host "New device: $($event.data.hostname)"
        # Add to AD, update DNS, etc.
    }
    "device.deleted" {
        Write-Host "Device removed: $($event.data.hostname)"
        # Clean up resources
    }
}

Best Practices

  1. Use Secrets: Always configure a secret for signature verification
  2. Minimal Events: Subscribe only to events you need
  3. Timeouts: Set appropriate timeouts for your endpoint
  4. Retries: Configure retry count based on endpoint reliability
  5. Monitoring: Check delivery history for failed webhooks
  6. Idempotency: Handle duplicate deliveries using the delivery_id
  7. HTTPS: Always use HTTPS endpoints for security