Commit eab5e060 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #48605 from CaoShuFeng/json_log

Automatic merge from submit-queue (batch tested with PRs 48583, 48605, 48601) support json output for log backend of advanced audit **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # **Special notes for your reviewer**: **Release note**: ``` Add json format support for advanced audit in apiserver. Use --audit-log-format=json to emit json to log backend. ```
parents 9c86d747 bc94370e
...@@ -23,11 +23,14 @@ go_test( ...@@ -23,11 +23,14 @@ go_test(
deps = [ deps = [
"//vendor/k8s.io/api/authentication/v1:go_default_library", "//vendor/k8s.io/api/authentication/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library", "//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
...@@ -35,6 +38,7 @@ go_test( ...@@ -35,6 +38,7 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/plugin/pkg/audit/log:go_default_library", "//vendor/k8s.io/apiserver/plugin/pkg/audit/log:go_default_library",
"//vendor/k8s.io/apiserver/plugin/pkg/audit/webhook:go_default_library",
], ],
) )
......
...@@ -63,6 +63,7 @@ type AuditLogOptions struct { ...@@ -63,6 +63,7 @@ type AuditLogOptions struct {
MaxAge int MaxAge int
MaxBackups int MaxBackups int
MaxSize int MaxSize int
Format string
} }
// AuditWebhookOptions control the webhook configuration for audit events. // AuditWebhookOptions control the webhook configuration for audit events.
...@@ -78,6 +79,7 @@ type AuditWebhookOptions struct { ...@@ -78,6 +79,7 @@ type AuditWebhookOptions struct {
func NewAuditOptions() *AuditOptions { func NewAuditOptions() *AuditOptions {
return &AuditOptions{ return &AuditOptions{
WebhookOptions: AuditWebhookOptions{Mode: pluginwebhook.ModeBatch}, WebhookOptions: AuditWebhookOptions{Mode: pluginwebhook.ModeBatch},
LogOptions: AuditLogOptions{Format: pluginlog.FormatLegacy},
} }
} }
...@@ -104,6 +106,18 @@ func (o *AuditOptions) Validate() []error { ...@@ -104,6 +106,18 @@ func (o *AuditOptions) Validate() []error {
if !validMode { if !validMode {
allErrors = append(allErrors, fmt.Errorf("invalid audit webhook mode %s, allowed modes are %q", o.WebhookOptions.Mode, strings.Join(pluginwebhook.AllowedModes, ","))) allErrors = append(allErrors, fmt.Errorf("invalid audit webhook mode %s, allowed modes are %q", o.WebhookOptions.Mode, strings.Join(pluginwebhook.AllowedModes, ",")))
} }
// check log format
validFormat := false
for _, f := range pluginlog.AllowedFormats {
if f == o.LogOptions.Format {
validFormat = true
break
}
}
if !validFormat {
allErrors = append(allErrors, fmt.Errorf("invalid audit log format %s, allowed formats are %q", o.LogOptions.Format, strings.Join(pluginlog.AllowedFormats, ",")))
}
} }
return allErrors return allErrors
} }
...@@ -161,6 +175,10 @@ func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) { ...@@ -161,6 +175,10 @@ func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
"The maximum number of old audit log files to retain.") "The maximum number of old audit log files to retain.")
fs.IntVar(&o.MaxSize, "audit-log-maxsize", o.MaxSize, fs.IntVar(&o.MaxSize, "audit-log-maxsize", o.MaxSize,
"The maximum size in megabytes of the audit log file before it gets rotated.") "The maximum size in megabytes of the audit log file before it gets rotated.")
fs.StringVar(&o.Format, "audit-log-format", o.Format,
"Format of saved audits. \"legacy\" indicates 1-line text format for each event."+
" \"json\" indicates structured json format. Requires the 'AdvancedAuditing' feature"+
" gate. Known formats are "+strings.Join(pluginlog.AllowedFormats, ",")+".")
} }
func (o *AuditLogOptions) getWriter() io.Writer { func (o *AuditLogOptions) getWriter() io.Writer {
...@@ -182,7 +200,7 @@ func (o *AuditLogOptions) getWriter() io.Writer { ...@@ -182,7 +200,7 @@ func (o *AuditLogOptions) getWriter() io.Writer {
func (o *AuditLogOptions) advancedApplyTo(c *server.Config) error { func (o *AuditLogOptions) advancedApplyTo(c *server.Config) error {
if w := o.getWriter(); w != nil { if w := o.getWriter(); w != nil {
c.AuditBackend = appendBackend(c.AuditBackend, pluginlog.NewBackend(w)) c.AuditBackend = appendBackend(c.AuditBackend, pluginlog.NewBackend(w, o.Format))
} }
return nil return nil
} }
......
...@@ -12,7 +12,9 @@ go_library( ...@@ -12,7 +12,9 @@ go_library(
srcs = ["backend.go"], srcs = ["backend.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
], ],
) )
...@@ -19,20 +19,38 @@ package log ...@@ -19,20 +19,38 @@ package log
import ( import (
"fmt" "fmt"
"io" "io"
"strings"
"k8s.io/apimachinery/pkg/runtime"
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
) )
const (
// FormatLegacy saves event in 1-line text format.
FormatLegacy = "legacy"
// FormatJson saves event in structured json format.
FormatJson = "json"
)
// AllowedFormats are the formats known by log backend.
var AllowedFormats = []string{
FormatLegacy,
FormatJson,
}
type backend struct { type backend struct {
out io.Writer out io.Writer
format string
} }
var _ audit.Backend = &backend{} var _ audit.Backend = &backend{}
func NewBackend(out io.Writer) *backend { func NewBackend(out io.Writer, format string) *backend {
return &backend{ return &backend{
out: out, out: out,
format: format,
} }
} }
...@@ -43,8 +61,23 @@ func (b *backend) ProcessEvents(events ...*auditinternal.Event) { ...@@ -43,8 +61,23 @@ func (b *backend) ProcessEvents(events ...*auditinternal.Event) {
} }
func (b *backend) logEvent(ev *auditinternal.Event) { func (b *backend) logEvent(ev *auditinternal.Event) {
line := audit.EventString(ev) line := ""
if _, err := fmt.Fprintln(b.out, line); err != nil { switch b.format {
case FormatLegacy:
line = audit.EventString(ev) + "\n"
case FormatJson:
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(auditv1alpha1.SchemeGroupVersion), ev)
if err != nil {
audit.HandlePluginError("log", err, ev)
return
}
line = string(bs[:])
default:
audit.HandlePluginError("log", fmt.Errorf("log format %q is not in list of known formats (%s)",
b.format, strings.Join(AllowedFormats, ",")), ev)
return
}
if _, err := fmt.Fprint(b.out, line); err != nil {
audit.HandlePluginError("log", err, ev) audit.HandlePluginError("log", err, ev)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment