|
| 1 | +// Copyright (c) F5, Inc. |
| 2 | +// |
| 3 | +// This source code is licensed under the Apache License, Version 2.0 license found in the |
| 4 | +// LICENSE file in the root directory of this source tree. |
| 5 | + |
| 6 | +package securityviolationsprocessor |
| 7 | + |
| 8 | +import ( |
| 9 | + "strings" |
| 10 | + |
| 11 | + events "github.com/nginx/agent/v3/api/grpc/events/v1" |
| 12 | +) |
| 13 | + |
| 14 | +// parseCSVLog parses comma-separated syslog messages where fields are in a |
| 15 | +// order : blocking_exception_reason,dest_port,ip_client,is_truncated_bool,method,policy_name,protocol,request_status,response_code,severity,sig_cves,sig_set_names,src_port,sub_violations,support_id,threat_campaign_names,violation_rating,vs_name,x_forwarded_for_header_value,outcome,outcome_reason,violations,violation_details,bot_signature_name,bot_category,bot_anomalies,enforced_bot_anomalies,client_class,client_application,client_application_version,transport_protocol,uri,request (secops_dashboard-log profile format). |
| 16 | +// versions when key-value logging isn't enabled. |
| 17 | +// |
| 18 | +//nolint:lll //long test string kept for log profile readability |
| 19 | +func (p *securityViolationsProcessor) parseCSVLog(message string) map[string]string { |
| 20 | + fieldValueMap := make(map[string]string) |
| 21 | + |
| 22 | + // Remove the "ASM:" prefix if present so we only process the values |
| 23 | + message = strings.TrimPrefix(message, "ASM:") |
| 24 | + |
| 25 | + fields := strings.Split(message, ",") |
| 26 | + |
| 27 | + // Mapping of CSV field positions to their corresponding keys |
| 28 | + fieldOrder := []string{ |
| 29 | + "blocking_exception_reason", |
| 30 | + "dest_port", |
| 31 | + "ip_client", |
| 32 | + "is_truncated_bool", |
| 33 | + "method", |
| 34 | + "policy_name", |
| 35 | + "protocol", |
| 36 | + "request_status", |
| 37 | + "response_code", |
| 38 | + "severity", |
| 39 | + "sig_cves", |
| 40 | + "sig_set_names", |
| 41 | + "src_port", |
| 42 | + "sub_violations", |
| 43 | + "support_id", |
| 44 | + "threat_campaign_names", |
| 45 | + "violation_rating", |
| 46 | + "vs_name", |
| 47 | + "x_forwarded_for_header_value", |
| 48 | + "outcome", |
| 49 | + "outcome_reason", |
| 50 | + "violations", |
| 51 | + "violation_details", |
| 52 | + "bot_signature_name", |
| 53 | + "bot_category", |
| 54 | + "bot_anomalies", |
| 55 | + "enforced_bot_anomalies", |
| 56 | + "client_class", |
| 57 | + "client_application", |
| 58 | + "client_application_version", |
| 59 | + "transport_protocol", |
| 60 | + "uri", |
| 61 | + "request", |
| 62 | + } |
| 63 | + |
| 64 | + for i, field := range fields { |
| 65 | + if i >= len(fieldOrder) { |
| 66 | + break |
| 67 | + } |
| 68 | + fieldValueMap[fieldOrder[i]] = strings.TrimSpace(field) |
| 69 | + } |
| 70 | + |
| 71 | + // combine multiple values separated by '::' |
| 72 | + if combined, ok := fieldValueMap["sig_cves"]; ok { |
| 73 | + parts := strings.SplitN(combined, "::", maxSplitParts) |
| 74 | + fieldValueMap["sig_ids"] = parts[0] |
| 75 | + if len(parts) > 1 { |
| 76 | + fieldValueMap["sig_names"] = parts[1] |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + if combined, ok := fieldValueMap["sig_set_names"]; ok { |
| 81 | + parts := strings.SplitN(combined, "::", maxSplitParts) |
| 82 | + fieldValueMap["sig_set_names"] = parts[0] |
| 83 | + if len(parts) > 1 { |
| 84 | + fieldValueMap["sig_cves"] = parts[1] |
| 85 | + } |
| 86 | + } |
| 87 | + |
| 88 | + return fieldValueMap |
| 89 | +} |
| 90 | + |
| 91 | +func (p *securityViolationsProcessor) mapKVToSecurityViolationEvent(log *events.SecurityViolationEvent, |
| 92 | + kvMap map[string]string, |
| 93 | +) { |
| 94 | + log.PolicyName = kvMap["policy_name"] |
| 95 | + log.SupportId = kvMap["support_id"] |
| 96 | + log.Outcome = kvMap["outcome"] |
| 97 | + log.OutcomeReason = kvMap["outcome_reason"] |
| 98 | + log.BlockingExceptionReason = kvMap["blocking_exception_reason"] |
| 99 | + log.Method = kvMap["method"] |
| 100 | + log.Protocol = kvMap["protocol"] |
| 101 | + log.XffHeaderValue = kvMap["x_forwarded_for_header_value"] |
| 102 | + log.Uri = kvMap["uri"] |
| 103 | + log.Request = kvMap["request"] |
| 104 | + log.IsTruncated = kvMap["is_truncated_bool"] |
| 105 | + log.RequestStatus = kvMap["request_status"] |
| 106 | + log.ResponseCode = kvMap["response_code"] |
| 107 | + log.ServerAddr = kvMap["server_addr"] |
| 108 | + log.VsName = kvMap["vs_name"] |
| 109 | + log.RemoteAddr = kvMap["ip_client"] |
| 110 | + log.DestinationPort = kvMap["dest_port"] |
| 111 | + log.ServerPort = kvMap["src_port"] |
| 112 | + log.Violations = kvMap["violations"] |
| 113 | + log.SubViolations = kvMap["sub_violations"] |
| 114 | + log.ViolationRating = kvMap["violation_rating"] |
| 115 | + log.SigSetNames = kvMap["sig_set_names"] |
| 116 | + log.SigCves = kvMap["sig_cves"] |
| 117 | + log.ClientClass = kvMap["client_class"] |
| 118 | + log.ClientApplication = kvMap["client_application"] |
| 119 | + log.ClientApplicationVersion = kvMap["client_application_version"] |
| 120 | + log.Severity = kvMap["severity"] |
| 121 | + log.ThreatCampaignNames = kvMap["threat_campaign_names"] |
| 122 | + log.BotAnomalies = kvMap["bot_anomalies"] |
| 123 | + log.BotCategory = kvMap["bot_category"] |
| 124 | + log.EnforcedBotAnomalies = kvMap["enforced_bot_anomalies"] |
| 125 | + log.BotSignatureName = kvMap["bot_signature_name"] |
| 126 | + log.InstanceTags = kvMap["instance_tags"] |
| 127 | + log.InstanceGroup = kvMap["instance_group"] |
| 128 | + log.DisplayName = kvMap["display_name"] |
| 129 | + |
| 130 | + if log.GetRemoteAddr() == "" { |
| 131 | + log.RemoteAddr = kvMap["remote_addr"] |
| 132 | + } |
| 133 | + if log.GetDestinationPort() == "" { |
| 134 | + log.DestinationPort = kvMap["remote_port"] |
| 135 | + } |
| 136 | +} |
0 commit comments