Files
kms/docs/documentation/platform/pki/alerting/webhook-alerts.mdx
zeekay 0ebffbd529 fix: white-label KMS branding and fix broken identifiers
- Fix 381 files where branding script corrupted variable names
  (e.g. isHanzo KMSTemplate -> isKmsTemplate)
- Rebrand from "Hanzo KMS" to just "KMS" for white-label support
  (allows Lux KMS, Hanzo KMS, etc. via configuration)
- 856 files, purely string replacements, no logic changes
2026-02-13 10:25:11 -08:00

115 lines
4.1 KiB
Plaintext

---
title: "Webhook Alerts"
sidebarTitle: "Webhook Alerts"
description: "Learn how to set up webhook notifications for PKI certificate alerts"
---
KMS can send PKI certificate alert notifications to a webhook URL. This guide walks through creating a webhook alert, the payload format, and how to verify webhook signatures.
## Guide to Creating a Webhook Alert
To create an alert, head to your Certificate Management Project > Alerting and press **Create Certificate Alert**.
![pki alerting](/images/platform/pki/alerting/alert-create.png)
![pki alerting modal](/images/platform/pki/alerting/alert-create-modal.png)
Here's some guidance for each field in the alert configuration sequence:
- **Alert Type**: The type of alert to create such as **Certificate Expiration**.
- **Alert Name**: A slug-friendly name for the alert such as `tls-expiry-alert`.
- **Description**: An optional description for the alert.
- **Alert Before**: The time before certificate expiration to trigger the alert such as 30 days denoted by `30d`.
- **Filters**: A list of filters that determine which certificates the alert applies to. Each row includes a **Field**, **Operator**, and **Value** to match against. For example, you can filter for certificates with a common name containing `example.com` by setting the field to **Common Name**, the operator to **Contains**, and the value to `example.com`.
Next, add a **Webhook** notification channel. The URL must use HTTPS. Optionally configure a signing secret to verify the authenticity of webhook payloads.
![pki alerting channels](/images/platform/pki/alerting/alert-create-channels.png)
## Webhook Payload Format
Webhook notifications are sent as HTTP POST requests with a [CloudEvents](https://cloudevents.io/)-compliant JSON payload.
```json
{
"specversion": "1.0",
"type": "com.kms.pki.certificate.expiration",
"source": "/projects/<project-id>/alerts/<alert-id>",
"id": "<unique-event-id>",
"time": "2024-01-15T10:30:00.000Z",
"datacontenttype": "application/json",
"subject": "certificate-expiration-alert",
"data": {
"alert": {
"id": "<alert-id>",
"name": "tls-expiry-alert",
"alertBefore": "30d",
"projectId": "<project-id>"
},
"certificates": [
{
"id": "<certificate-id>",
"serialNumber": "1234567890",
"commonName": "example.com",
"san": ["example.com", "www.example.com"],
"profileName": "TLS Server",
"notBefore": "2024-01-01T00:00:00.000Z",
"notAfter": "2024-12-31T23:59:59.000Z",
"status": "active",
"daysUntilExpiry": 30
}
],
"metadata": {
"totalCertificates": 1,
"viewUrl": "https://kms.hanzo.ai/cert-manager/<project-id>/policies"
}
}
}
```
## Webhook Signature Verification
If you configure a signing secret for your webhook channel, KMS will include an `x-kms-signature` header with each request. This allows you to verify that the webhook payload originated from KMS.
The header format is:
```
x-kms-signature: t=<timestamp>,v1=<signature>
```
Where:
- `<timestamp>` is the Unix timestamp (in milliseconds) when the signature was generated
- `v1` indicates the signature version
- `<signature>` is the HMAC-SHA256 signature of the payload
To verify the signature:
1. Extract the timestamp and signature from the header
2. Construct the signature payload by concatenating the timestamp, a period (`.`), and the raw request body: `{timestamp}.{body}`
3. Compute an HMAC-SHA256 hash using your signing secret
4. Compare the computed signature with the signature from the header
Example verification in Node.js:
```javascript
const crypto = require('crypto');
function verifyWebhookSignature(header, body, secret) {
// Parse header format: t=<timestamp>,v1=<signature>
const parts = header.split(',');
const timestamp = parts[0].replace('t=', '');
const signature = parts[1].replace('v1=', '');
const signaturePayload = `${timestamp}.${body}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signaturePayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
```