Routing Patterns
Production routing patterns for the QRadar → Sentinel migration. These patterns implement the CHLA filtering strategy to reduce Sentinel costs by 50-70% while maintaining compliance.
Routing Strategy
Destination Matrix
| Destination | What Goes There | Volume | Cost Impact |
|---|---|---|---|
Sentinel |
Critical security events |
~20-30% of logs |
Paid per GB |
S3 Archive |
Compliance retention |
~70-80% of logs |
Cheap storage |
Decision Logic
IF security_relevant THEN
route → Sentinel
ELSE
route → S3 (compliance archive)
END
ISE RADIUS Routing
Critical → Sentinel
| Condition | Description | MITRE |
|---|---|---|
|
Authentication failures |
T1078 |
|
Posture check failures |
T1190 |
|
Authorization denials |
T1078 |
|
Change of Authorization |
T1078 |
jq Transform:
# ISE RADIUS - Route auth failures to Sentinel
if (.ise.auth_result == "FAILED" or
.ise.posture_status == "NonCompliant" or
.ise.authorization_profile == "DENY_ACCESS" or
.ise.coa_action == "reauth") then
. + {
"route": "sentinel",
"category": "ise_security",
"mitre_technique": "T1078"
}
else
. + {
"route": "s3_archive",
"category": "ise_accounting"
}
end
Archive → S3
| Condition | Description |
|---|---|
|
Successful authentications |
|
Session accounting records |
|
Periodic health checks |
ISE TACACS Routing
Critical → Sentinel
| Condition | Description | MITRE |
|---|---|---|
|
Configuration changes |
T1059 |
|
Elevated privilege commands |
T1059 |
|
Admin auth failures |
T1078 |
jq Transform:
# ISE TACACS - Route admin actions to Sentinel
if (.tacacs.command_type == "config" or
.tacacs.privilege_level >= 7 or
.tacacs.auth_result == "FAILED") then
. + {
"route": "sentinel",
"category": "tacacs_admin",
"mitre_technique": "T1059"
}
else
. + {
"route": "s3_archive",
"category": "tacacs_accounting"
}
end
Archive → S3
| Condition | Description |
|---|---|
|
Read-only commands |
|
Session start records |
|
Session stop records |
FTD Firewall Routing
Critical → Sentinel
| Condition | Description | MITRE |
|---|---|---|
|
Blocked connections |
T1071 |
|
IDS/IPS alerts |
T1190 |
|
Malware detections |
T1204 |
|
High severity threats |
varies |
jq Transform:
# FTD Firewall - Route threats to Sentinel
if (.action == "deny" or
.action == "intrusion_detected" or
.action == "malware_detected" or
(.threat.severity | IN("critical", "high"))) then
# Determine MITRE technique
(if .action == "intrusion_detected" then "T1190"
elif .action == "malware_detected" then "T1204"
elif .threat.signature then "T1071"
else null end) as $mitre |
. + {
"route": "sentinel",
"category": "firewall_security",
"mitre_technique": $mitre
}
else
. + {
"route": "s3_archive",
"category": "firewall_flow"
}
end
Archive → S3
| Condition | Description |
|---|---|
|
Permitted traffic (flow logs) |
|
Connection terminations |
|
Traffic statistics |
ASA VPN Routing
Critical → Sentinel
| Condition | Description | MITRE |
|---|---|---|
|
VPN auth failures |
T1078 |
|
Client posture failures |
T1190 |
|
Admin VPN sessions |
T1133 |
jq Transform:
# ASA VPN - Route auth issues to Sentinel
if (.vpn.auth_result == "FAILED" or
.vpn.posture_status == "NonCompliant" or
.vpn.connection_type == "admin") then
. + {
"route": "sentinel",
"category": "vpn_security",
"mitre_technique": "T1133"
}
else
. + {
"route": "s3_archive",
"category": "vpn_session"
}
end
Network Device Routing
Critical → Sentinel
| Condition | Description | MITRE |
|---|---|---|
|
Configuration changes |
T1059 |
|
Interface failures |
- |
|
High severity events |
- |
jq Transform:
# Network Devices - Route config changes and alerts
if (.event_type == "config_change" or
.event_type == "interface_down" or
(.severity | IN("emergency", "alert", "critical"))) then
. + {
"route": "sentinel",
"category": "network_alert"
}
else
. + {
"route": "s3_archive",
"category": "network_info"
}
end
Combined Multi-Source Transform
Master routing transform for all sources:
# CHLA Master Routing Transform
# Handles: ISE RADIUS, ISE TACACS, FTD, ASA VPN, Network
# Detect source type
(
if .ise.auth_result then "ise_radius"
elif .tacacs then "ise_tacacs"
elif .vpn then "asa_vpn"
elif .action and (.src.zone or .dst.zone) then "ftd"
elif .device.type | IN("switch", "router", "wlc") then "network"
else "unknown"
end
) as $source |
# Determine routing based on source and conditions
(
if $source == "ise_radius" then
if (.ise.auth_result == "FAILED" or .ise.posture_status == "NonCompliant") then
{"route": "sentinel", "mitre": "T1078"}
else
{"route": "s3_archive"}
end
elif $source == "ise_tacacs" then
if (.tacacs.command_type == "config" or .tacacs.auth_result == "FAILED") then
{"route": "sentinel", "mitre": "T1059"}
else
{"route": "s3_archive"}
end
elif $source == "ftd" then
if (.action == "deny" or .threat.signature) then
{"route": "sentinel", "mitre": (if .threat then "T1071" else null end)}
else
{"route": "s3_archive"}
end
elif $source == "asa_vpn" then
if (.vpn.auth_result == "FAILED") then
{"route": "sentinel", "mitre": "T1133"}
else
{"route": "s3_archive"}
end
elif $source == "network" then
if (.event_type == "config_change" or .severity | IN("emergency", "alert", "critical")) then
{"route": "sentinel"}
else
{"route": "s3_archive"}
end
else
{"route": "s3_archive"}
end
) as $routing |
# Apply routing
. + $routing + {"log_source": $source}
Volume Estimates
| Source | Total Volume | → Sentinel | → S3 |
|---|---|---|---|
ISE RADIUS |
10 GB/day |
~2 GB (20%) |
~8 GB (80%) |
ISE TACACS |
1 GB/day |
~0.3 GB (30%) |
~0.7 GB (70%) |
FTD |
15 GB/day |
~3 GB (20%) |
~12 GB (80%) |
ASA VPN |
2 GB/day |
~0.4 GB (20%) |
~1.6 GB (80%) |
Network |
5 GB/day |
~0.5 GB (10%) |
~4.5 GB (90%) |
TOTAL |
33 GB/day |
~6 GB (18%) |
~27 GB (82%) |
Cost Savings: ~80% reduction in Sentinel ingestion costs.
Compliance Considerations
S3 Archive Requirements
| Requirement | Implementation |
|---|---|
Retention |
7 years (HIPAA) |
Encryption |
SSE-S3 or SSE-KMS |
Access Control |
IAM policies, no public access |
Audit Trail |
S3 access logging enabled |
Sentinel Data Needs
All security-relevant events must reach Sentinel for:
-
Real-time alerting
-
Threat hunting
-
Incident response
-
Compliance reporting
Testing Routing
Validate with Synthetic Logs
# Generate test logs and verify routing
./examples/monad/testing/synthetic-logs.sh <pipeline-id> 10
# Check pipeline logs
monad_logs_pipeline <pipeline-id> | jq '.logs[-10:] | .[] | {route, category, mitre_technique}'
Spot Check Production
# Sample recent logs
monad_logs_pipeline <pipeline-id> | jq '
.logs |
group_by(.route) |
map({route: .[0].route, count: length})
'
Key Takeaways
-
Security events → Sentinel (auth failures, threats, config changes)
-
Everything else → S3 (successful auths, flows, accounting)
-
MITRE tagging enables hunting - Add technique IDs
-
Volume reduction 70-80% - Major cost savings
-
Compliance retained - S3 archive meets HIPAA
-
Test before production - Validate routing logic
Next Module
Hands-On Lab - Practice with synthetic logs.