Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions internal/components/monitor/diagnostics/kql.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,27 @@ var logLevelPrefixes = map[string]string{
"error": "E",
}

// Audit log categories that use different log level format
var auditCategories = map[string]bool{
"kube-audit": true,
"kube-audit-admin": true,
}

// isAuditCategory checks if the given category is an audit log category
func isAuditCategory(category string) bool {
return auditCategories[category]
}

// BuildSafeKQLQuery builds pre-validated KQL queries to prevent injection, scoped to specific AKS cluster
func BuildSafeKQLQuery(category, logLevel string, maxRecords int, clusterResourceID string) string {
// Convert resource ID to uppercase as it's stored in uppercase in Log Analytics
upperResourceID := strings.ToUpper(clusterResourceID)
baseQuery := fmt.Sprintf("AzureDiagnostics | where Category == '%s' and ResourceId == '%s'", category, upperResourceID)

if logLevel != "" {
// Filter by log level using the predefined mapping
if logLevel != "" && !isAuditCategory(category) {
// For Kubernetes component logs (not audit), use the log_s prefix pattern
// Kubernetes logs use format like "I0715" (Info), "W0715" (Warning), "E0715" (Error)
// Audit logs don't follow this pattern, so we skip log level filtering for them
if prefix, exists := logLevelPrefixes[strings.ToLower(logLevel)]; exists {
baseQuery += fmt.Sprintf(" | where log_s startswith '%s'", prefix)
}
Expand Down
30 changes: 30 additions & 0 deletions internal/components/monitor/diagnostics/kql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,36 @@ func TestBuildSafeKQLQuery(t *testing.T) {
"limit 1000",
},
},
{
name: "query with audit category and log level - should skip log level filtering",
category: "kube-audit",
logLevel: "info",
maxRecords: 500,
clusterResourceID: "/subscriptions/test/resourcegroups/rg/providers/microsoft.containerservice/managedclusters/cluster",
expectedContains: []string{
"where Category == 'kube-audit'",
"limit 500",
},
notExpected: []string{
"where log_s startswith",
"where Level ==",
},
},
{
name: "query with audit-admin category and log level - should skip log level filtering",
category: "kube-audit-admin",
logLevel: "error",
maxRecords: 200,
clusterResourceID: "/subscriptions/test/resourcegroups/rg/providers/microsoft.containerservice/managedclusters/cluster",
expectedContains: []string{
"where Category == 'kube-audit-admin'",
"limit 200",
},
notExpected: []string{
"where log_s startswith",
"where Level ==",
},
},
{
name: "query with cloud controller manager",
category: "cloud-controller-manager",
Expand Down
Loading