Datadog¶
Datadog alerts reach the platform through Halo's stock Datadog integration, which posts a webhook payload to your instance and opens a ticket. The vendor's setup gets alerts in the door. This page covers what we change on top of it, so an incoming alert lands as a properly typed, categorized Alert ticket that carries its technical detail and maps to your compliance framework automatically.
Quick Summary
- Follow Halo's guide for the base connection: the integration module, credentials, the API application, and the webhook.
- Point the payload at the Alert ticket type rather than the integration's default ticket type, so alerts enter the triage-and-escalate workflow.
- Set
category_1on every payload. Category is not cosmetic here -- it drives the framework control, requirement, and KSI linkage the platform derives automatically. - Reference custom fields by
name, not by numericid, so the same payload works in every instance. - Set the Incident SLA and a priority level on every payload -- priorities are scoped to their SLA, so one without the other is ambiguous.
- Datadog cannot vary a category or priority from a single webhook, so create one webhook per category and route monitors to the right one.
Navigation
Configuration > Integrations on the GRC-ITSM website navigation, then the Datadog module.
Start with the vendor guide¶
Halo documents the base integration end to end. Follow it first, then apply the refinements below to the webhook payload.
Datadog Integration (Halo guide 2283)
Its setup, in brief:
- Enable the Datadog module under Configuration > Integrations.
- Enter your Datadog Site URL and API Key, plus an Application Key if you are forwarding security signals.
- Create an API application in the platform (Client ID and Secret, Login Type: Agent) for Datadog to authenticate against.
- In Datadog, add an Auth Method using OAuth 2.0 client credentials pointed at your token endpoint.
- Create the webhook, pointed at
https://<your instance>/api/notify/datadog. - Notify the webhook from a monitor or detection rule with
@webhook-<name>.
Everything from here changes only the webhook payload and how many webhooks you create.
Why the payload matters¶
The stock payload opens a ticket with a summary, a priority, and a link back to Datadog. That is enough to notice an alert, and not enough to work one. Three things follow from the payload in GRC-ITSM:
| What the payload sets | What it drives |
|---|---|
| Ticket type | Whether the alert enters the Alert triage workflow and can escalate in place to an Incident, carrying its history forward |
| Category | The framework linkage. The platform derives the FedRAMP controls, requirements, KSIs, and CMMC controls on a ticket from its category, so the category you set is what ties the alert to your compliance evidence |
| Custom fields | Whether a responder opens a ticket with the host, indicators, and detection source already in place, or has to pivot back to Datadog to find them |
Target the Alert ticket type¶
Set the ticket type explicitly in the payload rather than relying on the integration's Default Ticket Type:
21 is the Alert ticket type. Confirm the value in your own instance under Configuration > Ticket Types -- the ID appears in the URL when you open the type.
Alerts are the entry point for anything a monitoring or detection tool reports. After triage an alert is either resolved as benign or escalated in place to an Incident. See Alert for the workflow, and the Incident Response playbook for what happens after escalation.
Set the category¶
Category is the field that earns the most from this integration, because framework linkage derives from it. An uncategorized alert is a ticket nobody can trace to a control.
Add the full category path to the payload:
Use the path exactly as written, with > separators and no spaces around them. The Alert ticket type accepts these categories:
Security¶
| Category path |
|---|
Alerts and Incidents>Security |
Alerts and Incidents>Security>Audit Log Failure |
Alerts and Incidents>Security>Data Exfiltration |
Alerts and Incidents>Security>Denial of Service |
Alerts and Incidents>Security>Integrity Violation |
Alerts and Incidents>Security>Malware |
Alerts and Incidents>Security>Phishing |
Alerts and Incidents>Security>Policy Violation |
Alerts and Incidents>Security>Suspicious Activity |
Alerts and Incidents>Security>Unauthorized Access |
Alerts and Incidents>Security>Unauthorized Change |
Alerts and Incidents>Security>Unauthorized Software |
Availability¶
| Category path |
|---|
Alerts and Incidents>Availability |
Alerts and Incidents>Availability>Automation Error |
Alerts and Incidents>Availability>Backup Failure |
Alerts and Incidents>Availability>KSI |
Alerts and Incidents>Availability>Resource Exhaustion |
Alerts and Incidents>Availability>Security Functionality |
Alerts and Incidents>Availability>System Error |
Alerts and Incidents>Availability>System Outage |
Performance¶
| Category path |
|---|
Alerts and Incidents>Performance |
Alerts and Incidents>Performance>Disk Full |
Alerts and Incidents>Performance>High Resource Usage |
Alerts and Incidents>Performance>Network Latency |
Alerts and Incidents on its own is valid when no child fits, but prefer the most specific category that applies -- the more precise the category, the more precise the derived control linkage.
One webhook per category
A Datadog webhook sends a fixed payload, and Datadog's alert variables return display strings ($PRIORITY returns values like normal) that will not match a category path or a numeric priority. You cannot select a category dynamically from one webhook.
Create one webhook per category you actually use -- Halo-Alert-Security-Malware, Halo-Alert-Availability-System-Outage, and so on -- each with its category and priority hard-coded, then point each monitor or detection rule at the matching one with @webhook-<name>. This is the standard pattern for any field a Datadog variable cannot express.
Set the SLA and priority¶
Alerts run on the Incident SLA, which tracks both a response and a resolution clock. Priority levels in the platform are scoped to their SLA, so a priority level only means what you intend when the SLA is set alongside it. Send both:
The Incident SLA's levels:
priority_id |
Priority | Response target | Resolution target |
|---|---|---|---|
1 |
Critical | 0.5 hours | 1 hour |
2 |
High | 1 hour | 4 hours |
3 |
Medium | 4 hours | 8 hours |
4 |
Low | 8 hours | 24 hours |
Choose the level deliberately, because the clock starts the moment the ticket opens. An automated alert firing overnight at Critical carries a 30-minute response target, so reserve level 1 for conditions that genuinely warrant waking someone. Confirm the SLA and priority IDs in your own instance under Configuration > Service Level Agreements.
Map the Alert custom fields¶
Reference custom fields by name rather than by the numeric id the vendor guide uses. Field IDs differ between instances, so a payload built on IDs breaks the moment it is reused; names are stable:
The Alert ticket type carries these fields:
| Field | Name to use in the payload | Populate from the webhook? |
|---|---|---|
| Detection Source | CFDetectionSource |
Yes -- static. Datadog for monitors; add $SECURITY_RULE_NAME for signals so the ticket names the rule that fired |
| Internal Indicators | CFInternalIndicators |
Yes -- $HOSTNAME for the affected host, and $ALERT_SCOPE for the tags that triggered the alert |
| External Indicators | CFExternalIndicators |
No -- Datadog exposes no scalar variable for a client IP or domain. Fill during triage; see the warning below |
| Related CVEs | CFRelatedCVEs |
No -- no webhook variable carries a CVE. Fill during triage |
| MITRE Tactics | CFMITRETactics |
No -- no variable carries it. Fill during triage; see MITRE fields below |
| MITRE Techniques | CFMITRETechniques |
No -- fill during triage |
| MITRE Subtechniques | CFMITRESubtechniques |
No -- fill during triage |
| Root Cause | CFrootcauses |
No -- After Action Report field, written during response |
| Lessons Learned | CFLessonsLearned |
No -- After Action Report field |
| Corrective Actions | CFCorrectiveActions |
No -- After Action Report field |
Field names are case-sensitive and must be sent exactly as shown, including CFrootcauses, whose lowercase spelling is deliberate and differs from the pattern the other fields follow.
The framework fields on the ticket (FedRAMP Controls, FedRAMP Requirements, FedRAMP KSIs, FedRAMP Rules, CMMC Controls, CMMC Requirements) are never set in the payload. They derive from the category.
Which Datadog variables are worth mapping¶
Datadog's webhook variables are fixed -- you cannot traverse into an object or transform a value in the payload. These are the ones that carry something a responder wants:
| Variable | Returns | Useful for |
|---|---|---|
$HOSTNAME |
The host associated with the event | Internal Indicators |
$ALERT_SCOPE |
Comma-separated triggering tags, e.g. availability-zone:us-east-1a, role:computing-node |
Internal Indicators -- often more useful than the hostname alone |
$ALERT_QUERY |
The monitor query that fired | Details, when the ticket needs the detection logic |
$ALERT_METRIC |
The metric name, e.g. system.load.1 |
Details on metric monitors |
$SECURITY_RULE_NAME |
The detection rule's name | Detection Source |
$SECURITY_RULE_TYPE |
The rule type, e.g. log_detection |
Detection Source, where you distinguish rule classes |
$SECURITY_SIGNAL_SEVERITY |
The signal's severity, on Cloud SIEM's info through critical scale |
Details -- it is a string, so it cannot drive priority_id |
$ALERT_TRANSITION |
Triggered, Re-Triggered, Recovered, Renotify, and similar |
Filtering which events open tickets at all -- see below |
$ALERT_CYCLE_KEY |
An ID linking every event from trigger through resolution | Correlating follow-up events to the original ticket |
Three fields have no usable source and belong to triage:
- External Indicators. Client IPs live inside
$SECURITY_SIGNAL_ATTRIBUTES, which returns an object such as{"network":{"client":{"ip":"1.2.3.4"}}, "service": ["agent"]}. There is no scalar variable for the IP alone, and no way to reach into the object from the payload. - Related CVEs. No webhook variable carries one.
- MITRE fields. Covered below.
MITRE fields¶
Datadog detection rules carry MITRE ATT&CK metadata as rule tags in the form tactic:TA0001-Initial-Access and technique:T1566-Phishing, and those tags are what place a rule on Datadog's ATT&CK map. No webhook variable exposes them, so they cannot travel with the alert.
Fill all three during triage. The responder has the signal in front of them and can read the rule's tags directly, which beats any value baked into a webhook -- a payload's value would be wrong for every rule that does not happen to share it.
MITRE Tactics is a lookup field, so its value must match one of your instance's options exactly. Check the current options under Configuration > Custom Objects > Custom Fields. The platform's options correspond to the MITRE ATT&CK enterprise tactics, so a rule's tag translates directly:
| Datadog rule tag | Value to send |
|---|---|
tactic:TA0043-Reconnaissance |
Reconnaissance |
tactic:TA0042-Resource-Development |
Resource Development |
tactic:TA0001-Initial-Access |
Initial Access |
tactic:TA0002-Execution |
Execution |
tactic:TA0003-Persistence |
Persistence |
tactic:TA0004-Privilege-Escalation |
Privilege Escalation |
tactic:TA0005-Defense-Evasion |
Defense Evasion |
tactic:TA0006-Credential-Access |
Credential Access |
tactic:TA0007-Discovery |
Discovery |
tactic:TA0008-Lateral-Movement |
Lateral Movement |
tactic:TA0009-Collection |
Collection |
tactic:TA0011-Command-and-Control |
Command & Control |
tactic:TA0010-Exfiltration |
Exfiltration |
tactic:TA0040-Impact |
Impact |
MITRE Techniques and MITRE Subtechniques are free-form, so a responder can paste the rule's technique tag, such as T1566-Phishing, as written.
The payload¶
Monitor alerts¶
For availability and performance monitors:
{
"datadog_id": "$ID",
"tickettype_id": "21",
"category_1": "Alerts and Incidents>Availability>System Outage",
"summary": "$EVENT_TITLE",
"details": "$TEXT_ONLY_MSG",
"sla_id": "3",
"priority_id": "2",
"customfields": [
{ "name": "CFDetectionSource", "value": "Datadog" },
{ "name": "CFInternalIndicators", "value": "Host: $HOSTNAME | Scope: $ALERT_SCOPE" },
{ "name": "CFExternalIndicators", "value": "" },
{ "name": "CFRelatedCVEs", "value": "" },
{ "name": "CFMITRETactics", "value": "" },
{ "name": "CFMITRETechniques", "value": "" },
{ "name": "CFMITRESubtechniques", "value": "" }
],
"new_external_link": {
"table_id": "1",
"module_id": "391",
"third_party_id": "$ID",
"third_party_url": "$LINK",
"third_party_desc": "$EVENT_TITLE"
}
}
Security signals¶
For Cloud SIEM detection rules, which carry signal context the monitor payload does not:
{
"datadog_id": "$ID",
"security_signal_id": "$SECURITY_SIGNAL_ID",
"tickettype_id": "21",
"category_1": "Alerts and Incidents>Security>Suspicious Activity",
"summary": "$EVENT_TITLE",
"details": "$EVENT_MSG",
"sla_id": "3",
"priority_id": "2",
"customfields": [
{ "name": "CFDetectionSource", "value": "Datadog Cloud SIEM: $SECURITY_RULE_NAME ($SECURITY_RULE_TYPE)" },
{ "name": "CFInternalIndicators", "value": "Host: $HOSTNAME | Scope: $ALERT_SCOPE" },
{ "name": "CFExternalIndicators", "value": "" },
{ "name": "CFRelatedCVEs", "value": "" },
{ "name": "CFMITRETactics", "value": "" },
{ "name": "CFMITRETechniques", "value": "" },
{ "name": "CFMITRESubtechniques", "value": "" }
],
"new_external_link": {
"table_id": "1",
"module_id": "391",
"third_party_id": "$ID",
"third_party_url": "$LINK",
"third_party_desc": "$SECURITY_SIGNAL_ID"
}
}
The empty fields are deliberate. They are carried in the payload as placeholders so the full Alert field set is visible in one place, and so anyone extending the webhook can see what is available without cross-referencing this page. Fill in any your own instance can supply -- a monitor that always covers one service might reasonably carry a static value another would not -- and delete the lines you do not want set. Confirm field names and lookup options against your instance under Configuration > Custom Objects > Custom Fields before relying on them.
Fire one test alert into a non-production instance before going live. MITRE Tactics is a lookup field, and how a given instance treats an empty value on a lookup is worth confirming rather than assuming -- if the blank placeholder is rejected, drop that line and set the field during triage instead.
Keep the vendor guide's datadog_id, security_signal_id, and new_external_link values as it defines them. The identifiers tie the ticket to the originating alert, and the external link is what lets a responder reach the Datadog graph or signal in one click.
Validate $SECURITY_SIGNAL_ATTRIBUTES before relying on it
It is tempting to map $SECURITY_SIGNAL_ATTRIBUTES into External Indicators to capture client IPs. That variable expands to a JSON object rather than a plain string, so placing it inside a quoted payload value can produce invalid JSON and a webhook that fails without warning -- and because detection rules cannot be test-fired, you would not find out until a real signal was dropped.
Leave External Indicators for triage unless you have confirmed the behavior with a live signal in a non-production instance first.
HIPAA-enabled Datadog organizations cannot send security signals to webhooks
Datadog does not deliver security notifications over webhooks for HIPAA-enabled accounts. If your organization is HIPAA-enabled, detection rules referencing Signals or Findings will not reach the platform through this integration; the notifications are simply not sent, so there is no later delivery to wait for. Confirm your organization's status with Datadog before building the security-signal path, and request an exception through your Datadog account team if you need it. Monitor alerts are unaffected.
Control which events open tickets¶
By default a webhook fires on every state change a monitor goes through, so a single flapping monitor can open a ticket on trigger, another on renotify, and another on recovery. $ALERT_TRANSITION identifies which is which, returning values including Triggered, Re-Triggered, Recovered, Renotify, Warn, and No Data.
Two ways to keep the queue clean:
-
Notify the webhook only on the transitions you want. A handle placed outside a conditional block fires on every state transition; one placed inside fires only when that condition matches. Wrapping the mention in the alert condition keeps recoveries from ever reaching the platform:
A webhook scoped this way still fires on renotification, since a renotify re-sends the alert message. - Include
$ALERT_TRANSITIONin the ticket details where you do forward multiple transitions, so a responder can see at a glance whether they are looking at a new condition or a repeat.
$ALERT_CYCLE_KEY stays constant from the moment an alert triggers until it resolves, which makes it the right identifier if you later automate matching follow-up events to an existing ticket rather than opening a new one.
Field reference¶
| Payload key | Source | Notes |
|---|---|---|
tickettype_id |
Static | The Alert ticket type |
category_1 |
Static, per webhook | Drives framework control linkage |
summary |
$EVENT_TITLE |
Becomes the ticket summary |
details |
$EVENT_MSG or $TEXT_ONLY_MSG |
$TEXT_ONLY_MSG strips Datadog's markdown, which reads better in the ticket body |
sla_id |
Static | The Incident SLA, which alerts run on |
priority_id |
Static, per webhook | Scoped to the SLA above. Datadog's $PRIORITY returns a display string, not an ID |
customfields[].name |
Static | Field names from the table above |
new_external_link |
$ID, $LINK |
The link back to Datadog |
Datadog allows each webhook request 15 seconds and retries up to five times on a 5XX response or an internal error, so a brief platform outage will not lose an alert outright.
Assets¶
The Alert ticket type carries the Asset field, but Datadog identifies a host by name and the platform links assets by record. Send $HOSTNAME into Internal Indicators as shown above, and link the asset during triage so the alert joins that asset's history. Where a monitor's hosts map predictably to inventory records, a ticket rule can match the hostname and set the asset automatically.
Verify the setup¶
- In Datadog, open the webhook and use Test Notifications to fire a sample monitor alert. Detection rules cannot be tested this way and require a real signal.
- Confirm the ticket opens as an Alert, not the integration's default type.
- Confirm the category is set and the framework fields populated from it.
- Confirm Detection Source and Internal Indicators carry values, and the Datadog link resolves.
- Run one alert all the way through triage, including escalation to an Incident, before pointing production monitors at the webhook.
This is an external connection
Datadog sits outside the platform, so this integration is a data flow crossing your authorization boundary. Document the interconnection in the System Security Plan, including what alert content leaves Datadog and enters the platform, and confirm the Datadog offering you use carries an authorization appropriate to your environment before enabling it in a FedRAMP or CUI boundary. See the Integrations overview for the full pre-enablement checklist.
Related documentation
- Alert ticket type -- the triage and escalation workflow these tickets enter
- Incident Response playbook -- what happens when an alert escalates
- Categories -- how categories drive framework linkage across ticket types
- Ticket Rules -- automating field updates after a ticket lands
- Incident Response Policy -- the governing policy for alert and incident handling