Skip to content

Commit 5115e08

Browse files
committed
kubeapiserver auditloganalyzer: spot handler panics in audit log
Don't let any useragent cause too many panics in apiserver
1 parent e440b10 commit 5115e08

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package auditloganalyzer
2+
3+
import (
4+
"sync"
5+
6+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
"k8s.io/apimachinery/pkg/types"
8+
"k8s.io/apimachinery/pkg/util/sets"
9+
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
10+
)
11+
12+
type apiserverPaniced struct {
13+
lock sync.Mutex
14+
panicEventsPerUserAgent map[string]sets.Set[types.UID]
15+
}
16+
17+
func CheckForApiserverPaniced() *apiserverPaniced {
18+
return &apiserverPaniced{
19+
panicEventsPerUserAgent: map[string]sets.Set[types.UID]{},
20+
}
21+
}
22+
23+
func (s *apiserverPaniced) HandleAuditLogEvent(auditEvent *auditv1.Event, beginning, end *metav1.MicroTime) {
24+
if beginning != nil && auditEvent.RequestReceivedTimestamp.Before(beginning) || end != nil && end.Before(&auditEvent.RequestReceivedTimestamp) {
25+
return
26+
}
27+
28+
if auditEvent.ResponseStatus == nil {
29+
return
30+
}
31+
if auditEvent.ResponseStatus.Code != 500 {
32+
return
33+
}
34+
35+
s.lock.Lock()
36+
defer s.lock.Unlock()
37+
38+
events, ok := s.panicEventsPerUserAgent[auditEvent.UserAgent]
39+
if !ok {
40+
events = sets.New[types.UID]()
41+
}
42+
events.Insert(auditEvent.AuditID)
43+
s.panicEventsPerUserAgent[auditEvent.UserAgent] = events
44+
}

pkg/monitortests/kubeapiserver/auditloganalyzer/handle_excessive_applies.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package auditloganalyzer
22

33
import (
4+
"strings"
5+
"sync"
6+
47
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
58
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
69
"k8s.io/apiserver/pkg/authentication/serviceaccount"
7-
"strings"
8-
"sync"
910
)
1011

1112
type excessiveApplies struct {

pkg/monitortests/kubeapiserver/auditloganalyzer/monitortest.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ type auditLogAnalyzer struct {
1919

2020
summarizer *summarizer
2121
excessiveApplyChecker *excessiveApplies
22+
apiserverPaniced *apiserverPaniced
2223
}
2324

2425
func NewAuditLogAnalyzer() monitortestframework.MonitorTest {
2526
return &auditLogAnalyzer{
2627
summarizer: NewAuditLogSummarizer(),
2728
excessiveApplyChecker: CheckForExcessiveApplies(),
29+
apiserverPaniced: CheckForApiserverPaniced(),
2830
}
2931
}
3032

@@ -42,6 +44,7 @@ func (w *auditLogAnalyzer) CollectData(ctx context.Context, storageDir string, b
4244
auditLogHandlers := []AuditEventHandler{
4345
w.summarizer,
4446
w.excessiveApplyChecker,
47+
w.apiserverPaniced,
4548
}
4649
err = GetKubeAuditLogSummary(ctx, kubeClient, &beginning, &end, auditLogHandlers)
4750

@@ -122,6 +125,35 @@ func (w *auditLogAnalyzer) EvaluateTestsFromConstructedIntervals(ctx context.Con
122125

123126
}
124127

128+
for userAgent, panics := range w.apiserverPaniced.panicEventsPerUserAgent {
129+
testName := fmt.Sprintf("user %s must not produce too many apiserver handler panics", userAgent)
130+
131+
failures := []string{}
132+
if len(panics) > 5 {
133+
ids := []string{}
134+
for _, id := range panics.UnsortedList() {
135+
ids = append(ids, string(id))
136+
}
137+
failures := append(failures, fmt.Sprintf("failed auditIDs: %s", strings.Join(ids, ",")))
138+
ret = append(ret,
139+
&junitapi.JUnitTestCase{
140+
Name: testName,
141+
FailureOutput: &junitapi.FailureOutput{
142+
Message: strings.Join(failures, "\n"),
143+
Output: "details in audit log",
144+
},
145+
},
146+
)
147+
} else {
148+
ret = append(ret,
149+
&junitapi.JUnitTestCase{
150+
Name: testName,
151+
},
152+
)
153+
}
154+
155+
}
156+
125157
return ret, nil
126158
}
127159

0 commit comments

Comments
 (0)