vendor dependencies

This commit is contained in:
Sergiusz Urbaniak 2019-04-24 11:06:03 +02:00
parent 604208ef4f
commit 72abf135d6
1156 changed files with 78178 additions and 105799 deletions

View file

@ -23,11 +23,14 @@ import (
"strings"
"time"
"github.com/golang/glog"
"github.com/spf13/pflag"
"gopkg.in/natefinch/lumberjack.v2"
"k8s.io/klog"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/audit"
@ -36,31 +39,46 @@ import (
"k8s.io/apiserver/pkg/server"
utilfeature "k8s.io/apiserver/pkg/util/feature"
pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
plugindynamic "k8s.io/apiserver/plugin/pkg/audit/dynamic"
pluginenforced "k8s.io/apiserver/plugin/pkg/audit/dynamic/enforced"
pluginlog "k8s.io/apiserver/plugin/pkg/audit/log"
plugintruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
pluginwebhook "k8s.io/apiserver/plugin/pkg/audit/webhook"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
restclient "k8s.io/client-go/rest"
)
const (
// Default configuration values for ModeBatch.
defaultBatchBufferSize = 10000 // Buffer up to 10000 events before starting discarding.
// These batch parameters are only used by the webhook backend.
defaultBatchMaxSize = 400 // Only send up to 400 events at a time.
defaultBatchMaxWait = 30 * time.Second // Send events at least twice a minute.
defaultBatchThrottleQPS = 10 // Limit the send rate by 10 QPS.
defaultBatchThrottleBurst = 15 // Allow up to 15 QPS burst.
)
func appendBackend(existing, newBackend audit.Backend) audit.Backend {
if existing == nil {
return newBackend
}
if newBackend == nil {
return existing
}
return audit.Union(existing, newBackend)
}
func advancedAuditingEnabled() bool {
return utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing)
}
type AuditOptions struct {
// Policy configuration file for filtering audit events that are captured.
// If unspecified, a default is provided.
PolicyFile string
// Plugin options
LogOptions AuditLogOptions
WebhookOptions AuditWebhookOptions
DynamicOptions AuditDynamicOptions
}
const (
@ -72,12 +90,17 @@ const (
// a set of events. This causes requests to the API server to wait for the
// flush before sending a response.
ModeBlocking = "blocking"
// ModeBlockingStrict is the same as ModeBlocking, except when there is
// a failure during audit logging at RequestReceived stage, the whole
// request to apiserver will fail.
ModeBlockingStrict = "blocking-strict"
)
// AllowedModes is the modes known for audit backends.
var AllowedModes = []string{
ModeBatch,
ModeBlocking,
ModeBlockingStrict,
}
type AuditBatchOptions struct {
@ -99,8 +122,6 @@ type AuditTruncateOptions struct {
}
// AuditLogOptions determines the output of the structured audit log by default.
// If the AdvancedAuditing feature is set to false, AuditLogOptions holds the legacy
// audit log writer.
type AuditLogOptions struct {
Path string
MaxAge int
@ -127,28 +148,39 @@ type AuditWebhookOptions struct {
GroupVersionString string
}
func NewAuditOptions() *AuditOptions {
defaultLogBatchConfig := pluginbuffered.NewDefaultBatchConfig()
defaultLogBatchConfig.ThrottleEnable = false
// AuditDynamicOptions control the configuration of dynamic backends for audit events
type AuditDynamicOptions struct {
// Enabled tells whether the dynamic audit capability is enabled.
Enabled bool
// Configuration for batching backend. This is currently only used as an override
// for integration tests
BatchConfig *pluginbuffered.BatchConfig
}
func NewAuditOptions() *AuditOptions {
return &AuditOptions{
WebhookOptions: AuditWebhookOptions{
InitialBackoff: pluginwebhook.DefaultInitialBackoff,
BatchOptions: AuditBatchOptions{
Mode: ModeBatch,
BatchConfig: pluginbuffered.NewDefaultBatchConfig(),
BatchConfig: defaultWebhookBatchConfig(),
},
TruncateOptions: NewAuditTruncateOptions(),
GroupVersionString: "audit.k8s.io/v1beta1",
GroupVersionString: "audit.k8s.io/v1",
},
LogOptions: AuditLogOptions{
Format: pluginlog.FormatJson,
BatchOptions: AuditBatchOptions{
Mode: ModeBlocking,
BatchConfig: defaultLogBatchConfig,
BatchConfig: defaultLogBatchConfig(),
},
TruncateOptions: NewAuditTruncateOptions(),
GroupVersionString: "audit.k8s.io/v1beta1",
GroupVersionString: "audit.k8s.io/v1",
},
DynamicOptions: AuditDynamicOptions{
Enabled: false,
BatchConfig: plugindynamic.NewDefaultWebhookBatchConfig(),
},
}
}
@ -169,19 +201,10 @@ func (o *AuditOptions) Validate() []error {
return nil
}
allErrors := []error{}
if !advancedAuditingEnabled() {
if len(o.PolicyFile) > 0 {
allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-policy-file", features.AdvancedAuditing))
}
if len(o.WebhookOptions.ConfigFile) > 0 {
allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-webhook-config-file", features.AdvancedAuditing))
}
}
var allErrors []error
allErrors = append(allErrors, o.LogOptions.Validate()...)
allErrors = append(allErrors, o.WebhookOptions.Validate()...)
allErrors = append(allErrors, o.DynamicOptions.Validate()...)
return allErrors
}
@ -210,11 +233,13 @@ func validateBackendBatchOptions(pluginName string, options AuditBatchOptions) e
if config.MaxBatchSize <= 0 {
return fmt.Errorf("invalid audit batch %s max batch size %v, must be a positive number", pluginName, config.MaxBatchSize)
}
if config.ThrottleQPS <= 0 {
return fmt.Errorf("invalid audit batch %s throttle QPS %v, must be a positive number", pluginName, config.ThrottleQPS)
}
if config.ThrottleBurst <= 0 {
return fmt.Errorf("invalid audit batch %s throttle burst %v, must be a positive number", pluginName, config.ThrottleBurst)
if config.ThrottleEnable {
if config.ThrottleQPS <= 0 {
return fmt.Errorf("invalid audit batch %s throttle QPS %v, must be a positive number", pluginName, config.ThrottleQPS)
}
if config.ThrottleBurst <= 0 {
return fmt.Errorf("invalid audit batch %s throttle burst %v, must be a positive number", pluginName, config.ThrottleBurst)
}
}
return nil
}
@ -222,6 +247,7 @@ func validateBackendBatchOptions(pluginName string, options AuditBatchOptions) e
var knownGroupVersions = []schema.GroupVersion{
auditv1alpha1.SchemeGroupVersion,
auditv1beta1.SchemeGroupVersion,
auditv1.SchemeGroupVersion,
}
func validateGroupVersionString(groupVersion string) error {
@ -250,8 +276,7 @@ func (o *AuditOptions) AddFlags(fs *pflag.FlagSet) {
}
fs.StringVar(&o.PolicyFile, "audit-policy-file", o.PolicyFile,
"Path to the file that defines the audit policy configuration. Requires the 'AdvancedAuditing' feature gate."+
" With AdvancedAuditing, a profile is required to enable auditing.")
"Path to the file that defines the audit policy configuration.")
o.LogOptions.AddFlags(fs)
o.LogOptions.BatchOptions.AddFlags(pluginlog.PluginName, fs)
@ -259,49 +284,102 @@ func (o *AuditOptions) AddFlags(fs *pflag.FlagSet) {
o.WebhookOptions.AddFlags(fs)
o.WebhookOptions.BatchOptions.AddFlags(pluginwebhook.PluginName, fs)
o.WebhookOptions.TruncateOptions.AddFlags(pluginwebhook.PluginName, fs)
o.DynamicOptions.AddFlags(fs)
}
func (o *AuditOptions) ApplyTo(c *server.Config) error {
func (o *AuditOptions) ApplyTo(
c *server.Config,
kubeClientConfig *restclient.Config,
informers informers.SharedInformerFactory,
processInfo *ProcessInfo,
webhookOptions *WebhookOptions,
) error {
if o == nil {
return nil
}
// Apply legacy audit options if advanced audit is not enabled.
if !advancedAuditingEnabled() {
return o.LogOptions.legacyApplyTo(c)
if c == nil {
return fmt.Errorf("server config must be non-nil")
}
// Apply advanced options if advanced audit is enabled.
// 1. Apply generic options.
if err := o.applyTo(c); err != nil {
// 1. Build policy checker
checker, err := o.newPolicyChecker()
if err != nil {
return err
}
// 2. Apply plugin options.
if err := o.LogOptions.advancedApplyTo(c); err != nil {
return err
// 2. Build log backend
var logBackend audit.Backend
if w := o.LogOptions.getWriter(); w != nil {
if checker == nil {
klog.V(2).Info("No audit policy file provided, no events will be recorded for log backend")
} else {
logBackend = o.LogOptions.newBackend(w)
}
}
if err := o.WebhookOptions.applyTo(c); err != nil {
// 3. Build webhook backend
var webhookBackend audit.Backend
if o.WebhookOptions.enabled() {
if checker == nil {
klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend")
} else {
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend()
if err != nil {
return err
}
}
}
groupVersion, err := schema.ParseGroupVersion(o.WebhookOptions.GroupVersionString)
if err != nil {
return err
}
if c.AuditBackend != nil && c.AuditPolicyChecker == nil {
glog.V(2).Info("No audit policy file provided for AdvancedAuditing, no events will be recorded.")
// 4. Apply dynamic options.
var dynamicBackend audit.Backend
if o.DynamicOptions.enabled() {
// if dynamic is enabled the webhook and log backends need to be wrapped in an enforced backend with the static policy
if webhookBackend != nil {
webhookBackend = pluginenforced.NewBackend(webhookBackend, checker)
}
if logBackend != nil {
logBackend = pluginenforced.NewBackend(logBackend, checker)
}
// build dynamic backend
dynamicBackend, checker, err = o.DynamicOptions.newBackend(c.ExternalAddress, kubeClientConfig, informers, processInfo, webhookOptions)
if err != nil {
return err
}
// union dynamic and webhook backends so that truncate options can be applied to both
dynamicBackend = appendBackend(webhookBackend, dynamicBackend)
dynamicBackend = o.WebhookOptions.TruncateOptions.wrapBackend(dynamicBackend, groupVersion)
} else if webhookBackend != nil {
// if only webhook is enabled wrap it in the truncate options
dynamicBackend = o.WebhookOptions.TruncateOptions.wrapBackend(webhookBackend, groupVersion)
}
// 5. Set the policy checker
c.AuditPolicyChecker = checker
// 6. Join the log backend with the webhooks
c.AuditBackend = appendBackend(logBackend, dynamicBackend)
if c.AuditBackend != nil {
klog.V(2).Infof("Using audit backend: %s", c.AuditBackend)
}
return nil
}
func (o *AuditOptions) applyTo(c *server.Config) error {
func (o *AuditOptions) newPolicyChecker() (policy.Checker, error) {
if o.PolicyFile == "" {
return nil
return nil, nil
}
p, err := policy.LoadPolicyFromFile(o.PolicyFile)
if err != nil {
return fmt.Errorf("loading audit policy file: %v", err)
return nil, fmt.Errorf("loading audit policy file: %v", err)
}
c.AuditPolicyChecker = policy.NewChecker(p)
return nil
return policy.NewChecker(p), nil
}
func (o *AuditBatchOptions) AddFlags(pluginName string, fs *pflag.FlagSet) {
@ -327,10 +405,26 @@ func (o *AuditBatchOptions) AddFlags(pluginName string, fs *pflag.FlagSet) {
"moment if ThrottleQPS was not utilized before. Only used in batch mode.")
}
type ignoreErrorsBackend struct {
audit.Backend
}
func (i *ignoreErrorsBackend) ProcessEvents(ev ...*auditinternal.Event) bool {
i.Backend.ProcessEvents(ev...)
return true
}
func (i *ignoreErrorsBackend) String() string {
return fmt.Sprintf("ignoreErrors<%s>", i.Backend)
}
func (o *AuditBatchOptions) wrapBackend(delegate audit.Backend) audit.Backend {
if o.Mode == ModeBlocking {
if o.Mode == ModeBlockingStrict {
return delegate
}
if o.Mode == ModeBlocking {
return &ignoreErrorsBackend{Backend: delegate}
}
return pluginbuffered.NewBackend(delegate, o.BatchConfig)
}
@ -355,7 +449,7 @@ func (o *AuditTruncateOptions) AddFlags(pluginName string, fs *pflag.FlagSet) {
"it is split into several batches of smaller size.")
fs.Int64Var(&o.TruncateConfig.MaxEventSize, fmt.Sprintf("audit-%s-truncate-max-event-size", pluginName),
o.TruncateConfig.MaxEventSize, "Maximum size of the audit event sent to the underlying backend. "+
"If the size of an event is greater than this number, first request and response are removed, and"+
"If the size of an event is greater than this number, first request and response are removed, and "+
"if this doesn't reduce the size enough, event is discarded.")
}
@ -369,7 +463,7 @@ func (o *AuditTruncateOptions) wrapBackend(delegate audit.Backend, gv schema.Gro
func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.Path, "audit-log-path", o.Path,
"If set, all requests coming to the apiserver will be logged to this file. '-' means standard out.")
fs.IntVar(&o.MaxAge, "audit-log-maxage", o.MaxBackups,
fs.IntVar(&o.MaxAge, "audit-log-maxage", o.MaxAge,
"The maximum number of days to retain old audit log files based on the timestamp encoded in their filename.")
fs.IntVar(&o.MaxBackups, "audit-log-maxbackup", o.MaxBackups,
"The maximum number of old audit log files to retain.")
@ -377,8 +471,8 @@ func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
"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, ",")+".")
" \"json\" indicates structured json format. Known formats are "+
strings.Join(pluginlog.AllowedFormats, ",")+".")
fs.StringVar(&o.GroupVersionString, "audit-log-version", o.GroupVersionString,
"API group and version used for serializing audit events written to log.")
}
@ -390,30 +484,29 @@ func (o *AuditLogOptions) Validate() []error {
}
var allErrors []error
if advancedAuditingEnabled() {
if err := validateBackendBatchOptions(pluginlog.PluginName, o.BatchOptions); err != nil {
allErrors = append(allErrors, err)
}
if err := o.TruncateOptions.Validate(pluginlog.PluginName); err != nil {
allErrors = append(allErrors, err)
}
if err := validateGroupVersionString(o.GroupVersionString); err != nil {
allErrors = append(allErrors, err)
}
if err := validateBackendBatchOptions(pluginlog.PluginName, o.BatchOptions); err != nil {
allErrors = append(allErrors, err)
}
if err := o.TruncateOptions.Validate(pluginlog.PluginName); err != nil {
allErrors = append(allErrors, err)
}
// Check log format
validFormat := false
for _, f := range pluginlog.AllowedFormats {
if f == o.Format {
validFormat = true
break
}
}
if !validFormat {
allErrors = append(allErrors, fmt.Errorf("invalid audit log format %s, allowed formats are %q", o.Format, strings.Join(pluginlog.AllowedFormats, ",")))
if err := validateGroupVersionString(o.GroupVersionString); err != nil {
allErrors = append(allErrors, err)
}
// Check log format
validFormat := false
for _, f := range pluginlog.AllowedFormats {
if f == o.Format {
validFormat = true
break
}
}
if !validFormat {
allErrors = append(allErrors, fmt.Errorf("invalid audit log format %s, allowed formats are %q", o.Format, strings.Join(pluginlog.AllowedFormats, ",")))
}
// Check validities of MaxAge, MaxBackups and MaxSize of log options, if file log backend is enabled.
if o.MaxAge < 0 {
@ -451,26 +544,17 @@ func (o *AuditLogOptions) getWriter() io.Writer {
return w
}
func (o *AuditLogOptions) advancedApplyTo(c *server.Config) error {
if w := o.getWriter(); w != nil {
groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
log := pluginlog.NewBackend(w, o.Format, groupVersion)
log = o.BatchOptions.wrapBackend(log)
log = o.TruncateOptions.wrapBackend(log, groupVersion)
c.AuditBackend = appendBackend(c.AuditBackend, log)
}
return nil
}
func (o *AuditLogOptions) legacyApplyTo(c *server.Config) error {
c.LegacyAuditWriter = o.getWriter()
return nil
func (o *AuditLogOptions) newBackend(w io.Writer) audit.Backend {
groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
log := pluginlog.NewBackend(w, o.Format, groupVersion)
log = o.BatchOptions.wrapBackend(log)
log = o.TruncateOptions.wrapBackend(log, groupVersion)
return log
}
func (o *AuditWebhookOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.ConfigFile, "audit-webhook-config-file", o.ConfigFile,
"Path to a kubeconfig formatted file that defines the audit webhook configuration."+
" Requires the 'AdvancedAuditing' feature gate.")
"Path to a kubeconfig formatted file that defines the audit webhook configuration.")
fs.DurationVar(&o.InitialBackoff, "audit-webhook-initial-backoff",
o.InitialBackoff, "The amount of time to wait before retrying the first failed request.")
fs.DurationVar(&o.InitialBackoff, "audit-webhook-batch-initial-backoff",
@ -487,17 +571,15 @@ func (o *AuditWebhookOptions) Validate() []error {
}
var allErrors []error
if advancedAuditingEnabled() {
if err := validateBackendBatchOptions(pluginwebhook.PluginName, o.BatchOptions); err != nil {
allErrors = append(allErrors, err)
}
if err := o.TruncateOptions.Validate(pluginwebhook.PluginName); err != nil {
allErrors = append(allErrors, err)
}
if err := validateBackendBatchOptions(pluginwebhook.PluginName, o.BatchOptions); err != nil {
allErrors = append(allErrors, err)
}
if err := o.TruncateOptions.Validate(pluginwebhook.PluginName); err != nil {
allErrors = append(allErrors, err)
}
if err := validateGroupVersionString(o.GroupVersionString); err != nil {
allErrors = append(allErrors, err)
}
if err := validateGroupVersionString(o.GroupVersionString); err != nil {
allErrors = append(allErrors, err)
}
return allErrors
}
@ -506,18 +588,102 @@ func (o *AuditWebhookOptions) enabled() bool {
return o != nil && o.ConfigFile != ""
}
func (o *AuditWebhookOptions) applyTo(c *server.Config) error {
if !o.enabled() {
return nil
}
// newUntruncatedBackend returns a webhook backend without the truncate options applied
// this is done so that the same trucate backend can wrap both the webhook and dynamic backends
func (o *AuditWebhookOptions) newUntruncatedBackend() (audit.Backend, error) {
groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff)
if err != nil {
return fmt.Errorf("initializing audit webhook: %v", err)
return nil, fmt.Errorf("initializing audit webhook: %v", err)
}
webhook = o.BatchOptions.wrapBackend(webhook)
webhook = o.TruncateOptions.wrapBackend(webhook, groupVersion)
c.AuditBackend = appendBackend(c.AuditBackend, webhook)
return nil
return webhook, nil
}
func (o *AuditDynamicOptions) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&o.Enabled, "audit-dynamic-configuration", o.Enabled,
"Enables dynamic audit configuration. This feature also requires the DynamicAuditing feature flag")
}
func (o *AuditDynamicOptions) enabled() bool {
return o.Enabled && utilfeature.DefaultFeatureGate.Enabled(features.DynamicAuditing)
}
func (o *AuditDynamicOptions) Validate() []error {
var allErrors []error
if o.Enabled && !utilfeature.DefaultFeatureGate.Enabled(features.DynamicAuditing) {
allErrors = append(allErrors, fmt.Errorf("--audit-dynamic-configuration set, but DynamicAuditing feature gate is not enabled"))
}
return allErrors
}
func (o *AuditDynamicOptions) newBackend(
hostname string,
kubeClientConfig *restclient.Config,
informers informers.SharedInformerFactory,
processInfo *ProcessInfo,
webhookOptions *WebhookOptions,
) (audit.Backend, policy.Checker, error) {
if err := validateProcessInfo(processInfo); err != nil {
return nil, nil, err
}
clientset, err := kubernetes.NewForConfig(kubeClientConfig)
if err != nil {
return nil, nil, err
}
if webhookOptions == nil {
webhookOptions = NewWebhookOptions()
}
checker := policy.NewDynamicChecker()
informer := informers.Auditregistration().V1alpha1().AuditSinks()
eventSink := &v1core.EventSinkImpl{Interface: clientset.CoreV1().Events(processInfo.Namespace)}
dc := &plugindynamic.Config{
Informer: informer,
BufferedConfig: o.BatchConfig,
EventConfig: plugindynamic.EventConfig{
Sink: eventSink,
Source: corev1.EventSource{
Component: processInfo.Name,
Host: hostname,
},
},
WebhookConfig: plugindynamic.WebhookConfig{
AuthInfoResolverWrapper: webhookOptions.AuthInfoResolverWrapper,
ServiceResolver: webhookOptions.ServiceResolver,
},
}
backend, err := plugindynamic.NewBackend(dc)
if err != nil {
return nil, nil, fmt.Errorf("could not create dynamic audit backend: %v", err)
}
return backend, checker, nil
}
// defaultWebhookBatchConfig returns the default BatchConfig used by the Webhook backend.
func defaultWebhookBatchConfig() pluginbuffered.BatchConfig {
return pluginbuffered.BatchConfig{
BufferSize: defaultBatchBufferSize,
MaxBatchSize: defaultBatchMaxSize,
MaxBatchWait: defaultBatchMaxWait,
ThrottleEnable: true,
ThrottleQPS: defaultBatchThrottleQPS,
ThrottleBurst: defaultBatchThrottleBurst,
AsyncDelegate: true,
}
}
// defaultLogBatchConfig returns the default BatchConfig used by the Log backend.
func defaultLogBatchConfig() pluginbuffered.BatchConfig {
return pluginbuffered.BatchConfig{
BufferSize: defaultBatchBufferSize,
// Batching is not useful for the log-file backend.
// MaxBatchWait ignored.
MaxBatchSize: 1,
ThrottleEnable: false,
// Asynchronous log threads just create lock contention.
AsyncDelegate: false,
}
}