Skip to content

Commit

Permalink
Enable full advanced audit in origin
Browse files Browse the repository at this point in the history
  • Loading branch information
soltysh committed Sep 4, 2017
1 parent b797b97 commit aad80e2
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 19 deletions.
4 changes: 4 additions & 0 deletions contrib/completions/bash/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -37661,6 +37661,8 @@ _openshift_start_kubernetes_apiserver()
local_nonpersistent_flags+=("--anonymous-auth")
flags+=("--apiserver-count=")
local_nonpersistent_flags+=("--apiserver-count=")
flags+=("--audit-log-format=")
local_nonpersistent_flags+=("--audit-log-format=")
flags+=("--audit-log-maxage=")
local_nonpersistent_flags+=("--audit-log-maxage=")
flags+=("--audit-log-maxbackup=")
Expand Down Expand Up @@ -38717,6 +38719,8 @@ _openshift_start_template-service-broker()
flags_with_completion=()
flags_completion=()

flags+=("--audit-log-format=")
local_nonpersistent_flags+=("--audit-log-format=")
flags+=("--audit-log-maxage=")
local_nonpersistent_flags+=("--audit-log-maxage=")
flags+=("--audit-log-maxbackup=")
Expand Down
4 changes: 4 additions & 0 deletions contrib/completions/zsh/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -37810,6 +37810,8 @@ _openshift_start_kubernetes_apiserver()
local_nonpersistent_flags+=("--anonymous-auth")
flags+=("--apiserver-count=")
local_nonpersistent_flags+=("--apiserver-count=")
flags+=("--audit-log-format=")
local_nonpersistent_flags+=("--audit-log-format=")
flags+=("--audit-log-maxage=")
local_nonpersistent_flags+=("--audit-log-maxage=")
flags+=("--audit-log-maxbackup=")
Expand Down Expand Up @@ -38866,6 +38868,8 @@ _openshift_start_template-service-broker()
flags_with_completion=()
flags_completion=()

flags+=("--audit-log-format=")
local_nonpersistent_flags+=("--audit-log-format=")
flags+=("--audit-log-maxage=")
local_nonpersistent_flags+=("--audit-log-maxage=")
flags+=("--audit-log-maxbackup=")
Expand Down
12 changes: 11 additions & 1 deletion pkg/cmd/server/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,6 @@ type AggregatorConfig struct {
// AuditConfig holds configuration for the audit capabilities
type AuditConfig struct {
// If this flag is set, audit log will be printed in the logs.
// The logs contains, method, user and a requested URL.
Enabled bool
// All requests coming to the apiserver will be logged to this file.
AuditFilePath string
Expand All @@ -474,6 +473,17 @@ type AuditConfig struct {
MaximumRetainedFiles int
// Maximum size in megabytes of the log file before it gets rotated. Defaults to 100MB.
MaximumFileSizeMegabytes int

// Path to the file that defines the audit policy configuration.
PolicyFile string

// Format of saved audits (legacy or json).
LogFormat string

// Path to a kubeconfig formatted filpe that defines the audit webhook configuration.
WebhookConfigFile string
// Strategy for sending audit events (block or batch).
WebhookMode string
}

// JenkinsPipelineConfig holds configuration for the Jenkins pipeline strategy
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/server/api/v1/swagger_doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ var map_AuditConfig = map[string]string{
"maximumFileRetentionDays": "Maximum number of days to retain old log files based on the timestamp encoded in their filename.",
"maximumRetainedFiles": "Maximum number of old log files to retain.",
"maximumFileSizeMegabytes": "Maximum size in megabytes of the log file before it gets rotated. Defaults to 100MB.",
"policyFile": "Path to the file that defines the audit policy configuration.",
"logFormat": "Format of saved audits (legacy or json).",
"webhookConfigFile": "Path to a kubeconfig formatted filpe that defines the audit webhook configuration.",
"webhookMode": "Strategy for sending audit events (block or batch).",
}

func (AuditConfig) SwaggerDoc() map[string]string {
Expand Down
11 changes: 11 additions & 0 deletions pkg/cmd/server/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,17 @@ type AuditConfig struct {
MaximumRetainedFiles int `json:"maximumRetainedFiles"`
// Maximum size in megabytes of the log file before it gets rotated. Defaults to 100MB.
MaximumFileSizeMegabytes int `json:"maximumFileSizeMegabytes"`

// Path to the file that defines the audit policy configuration.
PolicyFile string `json:"policyFile"`

// Format of saved audits (legacy or json).
LogFormat string `json:"logFormat"`

// Path to a kubeconfig formatted filpe that defines the audit webhook configuration.
WebhookConfigFile string `json:"webhookConfigFile"`
// Strategy for sending audit events (block or batch).
WebhookMode string `json:"webhookMode"`
}

// JenkinsPipelineConfig holds configuration for the Jenkins pipeline strategy
Expand Down
24 changes: 24 additions & 0 deletions pkg/cmd/server/api/validation/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
kuval "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
auditpolicy "k8s.io/apiserver/pkg/audit/policy"
auditlog "k8s.io/apiserver/plugin/pkg/audit/log"
auditwebhook "k8s.io/apiserver/plugin/pkg/audit/webhook"
apiserveroptions "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
kcmoptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
kvalidation "k8s.io/kubernetes/pkg/api/validation"
Expand Down Expand Up @@ -238,6 +241,9 @@ func ValidateAggregatorConfig(config api.AggregatorConfig, fldPath *field.Path)

func ValidateAuditConfig(config api.AuditConfig, fldPath *field.Path) ValidationResults {
validationResults := ValidationResults{}
if !config.Enabled {
return validationResults
}

if len(config.AuditFilePath) == 0 {
// for backwards compatibility reasons we can't error this out
Expand All @@ -253,6 +259,24 @@ func ValidateAuditConfig(config api.AuditConfig, fldPath *field.Path) Validation
validationResults.AddErrors(field.Invalid(fldPath.Child("maximumFileSizeMegabytes"), config.MaximumFileSizeMegabytes, "must be greater than or equal to 0"))
}

if len(config.PolicyFile) > 0 {
policy, err := auditpolicy.LoadPolicyFromFile(config.PolicyFile)
if err != nil {
validationResults.AddErrors(field.Invalid(fldPath.Child("policyFile"), config.PolicyFile, err.Error()))
}
if len(policy.Rules) == 0 {
validationResults.AddErrors(field.Invalid(fldPath.Child("policyFile"), config.PolicyFile, "a policy file with 0 policies is not valid"))
}
}
if len(config.LogFormat) > 0 && config.LogFormat != auditlog.FormatLegacy && config.LogFormat != auditlog.FormatJson {
validationResults.AddErrors(field.Invalid(fldPath.Child("logFormat"), config.LogFormat,
fmt.Sprintf("invalid audit log format, allowed formats are %q", strings.Join(auditlog.AllowedFormats, ","))))
}
if len(config.WebhookMode) > 0 && config.WebhookMode != auditwebhook.ModeBatch && config.WebhookMode != auditwebhook.ModeBlocking {
validationResults.AddErrors(field.Invalid(fldPath.Child("logFormat"), config.WebhookMode,
fmt.Sprintf("invalid audit webhook mode, allowed modes are %q", strings.Join(auditwebhook.AllowedModes, ","))))
}

return validationResults
}

Expand Down
66 changes: 48 additions & 18 deletions pkg/cmd/server/origin/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import (

apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion"
auditinternal "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/apiserver/pkg/audit"
auditpolicy "k8s.io/apiserver/pkg/audit/policy"
apifilters "k8s.io/apiserver/pkg/endpoints/filters"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
apiserver "k8s.io/apiserver/pkg/server"
apiserverfilters "k8s.io/apiserver/pkg/server/filters"
auditlog "k8s.io/apiserver/plugin/pkg/audit/log"
auditwebhook "k8s.io/apiserver/plugin/pkg/audit/webhook"
aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
kubeapiserver "k8s.io/kubernetes/pkg/master"
kcorestorage "k8s.io/kubernetes/pkg/registry/core/rest"
Expand Down Expand Up @@ -291,24 +293,8 @@ func (c *MasterConfig) buildHandlerChain() (func(apiHandler http.Handler, kc *ap
handler = serverhandlers.ImpersonationFilter(handler, c.Authorizer, cache.NewGroupCache(c.UserInformers.User().InternalVersion().Groups()), genericConfig.RequestContextMapper)
// audit handler must comes before the impersonationFilter to read the original user
if c.Options.AuditConfig.Enabled {
var writer io.Writer
if len(c.Options.AuditConfig.AuditFilePath) > 0 {
writer = &lumberjack.Logger{
Filename: c.Options.AuditConfig.AuditFilePath,
MaxAge: c.Options.AuditConfig.MaximumFileRetentionDays,
MaxBackups: c.Options.AuditConfig.MaximumRetainedFiles,
MaxSize: c.Options.AuditConfig.MaximumFileSizeMegabytes,
}
} else {
// backwards compatible writer to regular log
writer = cmdutil.NewGLogWriterV(0)
}
c.AuditBackend = auditlog.NewBackend(writer)
auditPolicyChecker := auditpolicy.NewChecker(&auditinternal.Policy{
// This is for backwards compatibility maintaining the old visibility, ie. just
// raw overview of the requests comming in.
Rules: []auditinternal.PolicyRule{{Level: auditinternal.LevelMetadata}},
})
var auditPolicyChecker auditpolicy.Checker
c.AuditBackend, auditPolicyChecker = c.prepareAuditAssets()
handler = apifilters.WithAudit(handler, genericConfig.RequestContextMapper, c.AuditBackend, auditPolicyChecker, genericConfig.LongRunningFunc)
}
handler = apifilters.WithAuthentication(handler, c.RequestContextMapper, c.Authenticator, apifilters.Unauthorized(false))
Expand Down Expand Up @@ -340,6 +326,50 @@ func (c *MasterConfig) buildHandlerChain() (func(apiHandler http.Handler, kc *ap
nil
}

func (c *MasterConfig) prepareAuditAssets() (audit.Backend, auditpolicy.Checker) {
var writer io.Writer
if len(c.Options.AuditConfig.AuditFilePath) > 0 {
writer = &lumberjack.Logger{
Filename: c.Options.AuditConfig.AuditFilePath,
MaxAge: c.Options.AuditConfig.MaximumFileRetentionDays,
MaxBackups: c.Options.AuditConfig.MaximumRetainedFiles,
MaxSize: c.Options.AuditConfig.MaximumFileSizeMegabytes,
}
} else {
// backwards compatible writer to regular log
writer = cmdutil.NewGLogWriterV(0)
}
var backend audit.Backend = auditlog.NewBackend(writer, auditlog.FormatLegacy)
policyChecker := auditpolicy.NewChecker(&auditinternal.Policy{
// This is for backwards compatibility maintaining the old visibility, ie. just
// raw overview of the requests comming in.
Rules: []auditinternal.PolicyRule{{Level: auditinternal.LevelMetadata}},
})

// when policy file is defined we enable the advanced auditing
if len(c.Options.AuditConfig.PolicyFile) > 0 {
// policy configuration
p, _ := auditpolicy.LoadPolicyFromFile(c.Options.AuditConfig.PolicyFile)
policyChecker = auditpolicy.NewChecker(p)

// log configuration, only when file path was provided
if len(c.Options.AuditConfig.AuditFilePath) > 0 {
backend = auditlog.NewBackend(writer, c.Options.AuditConfig.LogFormat)
}

// webhook configuration, only when config file was provided
if len(c.Options.AuditConfig.WebhookConfigFile) > 0 {
webhook, err := auditwebhook.NewBackend(c.Options.AuditConfig.WebhookConfigFile, c.Options.AuditConfig.WebhookMode)
if err != nil {
glog.Fatalf("Audit webhook initialization failed: %v", err)
}
backend = audit.Union(backend, webhook)
}
}

return backend, policyChecker
}

func (c *MasterConfig) withConsoleRedirection(handler, assetServerHandler http.Handler, assetConfig *configapi.AssetConfig) http.Handler {
if assetConfig == nil {
return handler
Expand Down

0 comments on commit aad80e2

Please sign in to comment.