diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go index 6f850f728bfdb..25fe280a472e6 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go @@ -23,6 +23,7 @@ import ( "fmt" "net" "net/http" + "strings" "sync" "time" @@ -242,9 +243,34 @@ func (a *auditResponseWriter) processCode(code int) { }) } +func (a *auditResponseWriter) Header() http.Header { + if a.event.Annotations == nil { + a.event.Annotations = map[string]string{} + } + for name, value := range a.ResponseWriter.Header() { + switch { + case name == "Content-Type": + a.event.Annotations["openshift.io/response-header-content-type"] = strings.Join(value, ",") + case name == "Content-Encoding": + a.event.Annotations["openshift.io/response-header-content-encoding"] = strings.Join(value, ",") + case name == "Content-Length": + a.event.Annotations["openshift.io/response-header-content-length"] = strings.Join(value, ",") + } + } + return a.ResponseWriter.Header() +} + func (a *auditResponseWriter) Write(bs []byte) (int, error) { // the Go library calls WriteHeader internally if no code was written yet. But this will go unnoticed for us a.processCode(http.StatusOK) + if a.event.Annotations != nil { + if _, ok := a.event.Annotations["openshift.io/response-header-content-length"]; !ok { + contentLength := len(bs) + if contentLength > 500 { + a.event.Annotations["openshift.io/response-header-content-length"] = fmt.Sprintf("%d", len(bs)) + } + } + } return a.ResponseWriter.Write(bs) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index eeecebb9774db..af50c868936d6 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -1104,6 +1104,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.NonLongRunningRequestWaitGroup) handler = WithNonReadyRequestLogging(handler, c.lifecycleSignals.HasBeenReady) handler = WithLateConnectionFilter(handler) + handler = WithRequestHeaders(handler) if c.ShutdownWatchTerminationGracePeriod > 0 { handler = genericfilters.WithWatchTerminationDuringShutdown(handler, c.lifecycleSignals, c.WatchRequestWaitGroup) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go index a84494b1982db..6ce15f6f70bcf 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go @@ -217,6 +217,24 @@ func WithLateConnectionFilter(handler http.Handler) http.Handler { }) } +// WithRequestHeaders logs every non-probe request and logs interesting request headers. +func WithRequestHeaders(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if pth := "/" + strings.TrimLeft(r.URL.Path, "/"); pth != "/readyz" && pth != "/healthz" && pth != "/livez" { + if accept, ok := r.Header["Accept"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-accept", strings.Join(accept, ",")) + } + if accept_encoding, ok := r.Header["Accept-Encoding"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-accept-encoding", strings.Join(accept_encoding, ",")) + } + if content_length, ok := r.Header["Content-Length"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-content-length", strings.Join(content_length, ",")) + } + } + handler.ServeHTTP(w, r) + }) +} + // WithNonReadyRequestLogging rejects the request until the process has been ready once. func WithNonReadyRequestLogging(handler http.Handler, hasBeenReadySignal lifecycleSignal) http.Handler { if hasBeenReadySignal == nil {